题目:1.K倍区间
给定一个长度为 N的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj之和是 K的倍数
我们就称这个区间 [i,j]是 K倍区间。
你能求出数列中总共有多少个 K倍区间吗?
桶预处理:
对于这类问题,我们先要把ai-aj-b=0这一式子化为等式,即ai-b=aj
K倍区间是因为(s[i]-s[j])%k==0等价于s[i]%k-s[j]%k==0即s[i]%k==s[j]%k
先将所有s[i]%k装进桶中,然后从前往后扫描一边s[j]%k
扫描时,我们就只需从前往后统计有多少s[j]%k满足前面的s[i]%k
最后累加起来,累加这一步应用了组合数的思想
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100010;
int n, k;
LL a[N], s[N], cnt[N];
int main()
{
cin >> n >> k;
for(int i = 1; i <= n; i ++ ) cin >> a[i], s[i] = s[i - 1] + a[i];
LL res = 0;
cnt[0] = 1;
for(int i = 1; i <= n; i ++ )
{
res += cnt[s[i] % k];
cnt[s[i] % k] ++ ;
}
cout << res << endl;
return 0;
}
题目2.差分计数
给定n个整数a1,a2……,an和一个整数x。
求有多少有序对(i, j)满足a[i]-a[j]=x
数据范围:
n为2e6
ai为-2e6到2e6
输入样例:
5 1
1 1 5 4 2
输出样例:
3
分析题目的式子a[i]-a[j]==x,我们可以化成a[i]==a[j]-x,
因为a[i]可能为负数,为了防止溢出
因此我们可以先把所有的a[i]+N装进桶中,
从前往后扫描时我们统计有多少数量的a[j]-x+N即可
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2000010;
int n, x;
int a[N];
LL cnt[N];
int main()
{
cin >> n >> x;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ )
cnt[a[i] + N] ++ ;
LL res = 0;
for(int i = 1; i <= n; i ++ )
res += cnt[a[i] - x + N];
cout << res << endl;
return 0;
}