给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj之和是 KK 的倍数,我们就称这个区间 [i,j][i,j] 是 K 倍区间。
你能求出数列中总共有多少个 K 倍区间吗?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含一个整数 Ai。
输出格式
输出一个整数,代表 K 倍区间的数目。
数据范围
1≤N,K≤100000
1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
基本原理:首先,若s[i]%k==a且s[j]%k==a,那么说明s[i]-s[j]%一定为k的倍数.
与上一篇文章原理接近,先将所以前缀和数组s[N]%k,然后用数组sum[N]存放每个数出现的次数,随后遍历数组s[N],假设s[i]出现一次,则sum[s[i]]++,ans加上s[i]已出现的次数,具体原理如图:
1出现了五次,每出现一次sum[s[i]]++,ans+=sum[s[i]]。也可以用公式 n*(n-1) / 2 来计算。
这样把s[i]的每个数遍历一遍即可求出答案。
最后,如果s[i]本身就是k的倍数,那么自己就成一个答案,也就是说s[i]为0的时候,就自成一个答案。所以最终结果要加入sum[0]。
#include<iostream>
using namespace std;
const int N = 100010;
typedef long long LL;
int n,k;
int a[N],s[N];
int sum[N];
LL ans;
int main()
{
cin >> n >> k;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
s[i] = (s[i - 1] + a[i]) % k;
ans += sum[s[i]];
sum[s[i]]++;
}
cout << ans + sum[0] << endl;
}