首先,科普一个数学知识
- 若a%k==b%k,则|a-b|%k==0
所以,这一题我们可以用前缀和,结合这个数学知识解决
假设数列的前缀和用s存储
若s[i]%k==s[j]%k(i<j),则(s[j]-s[i])%k==0,所以a[i+1]~a[j]就是一个k倍区间
那么,在枚举到某个数s[j]时,我们怎么知道它前面出现的所有的i的个数,使得s[i]%k==s[j]%k呢,我们可以用一个数组存储,每次枚举,使cnt[s[i]%k]++;
- 注意:枚举我们可以从0开始,这样的话,cnt[0]初始时就为1,每次枚举到s[i]%k==0的状态时,我们加上cnt[0],就多加了一个1,正好就是a[i]本身了,只有一个元素的K倍区间
C++代码如下:
#include<iostream>
using namespace std;
const int N=100010;
typedef long long LL;//开Long long 防止爆int
int n,k;
int a[N];
LL s[N];//前缀和数组
int cnt[N];
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)s[i]=s[i-1]+a[i];
LL res=0;
for(int i=0;i<=n;i++){
int t=s[i]%k;
res+=cnt[t];//先加再给cnt[t]+1,不然就把自己也算上了
cnt[t]++;
}
cout<<res<<endl;
return 0;
}