题目描述:
主要思想:前缀和、同余组合
前缀和:
int n;
for(ll i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];//前缀和
}
解题思路:要求某个区间的之和是k的倍数。
设[L,R]为k倍子区间,利用前缀和计算[L,R]中的全部元素之和,即sum[R]-sum[L-1];
目标->(sum[R]-sum[L-1])%k=0
->sum[R]%k=sum[L-1]%k
将目标转换为求每个区间同余的自由组合问题,在同余组合中任选俩个形成一个k倍区间。k=0,1,2,...,k-1,每个情况组合总数是n*(n-1)/2;n (n是余数相等的个数)
同时还要注意:k=0时不止可以俩俩组合,它自身也是一个k倍区间。在最后结果还要加上余数为0自身形成k倍区间的情况数,即余数为0的区间个数。
完整代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,k,a,sum[100001]={0},cnt[100001]={0};
cin>>n>>k;
for(ll i=1;i<=n;i++)
{
cin>>a;
sum[i]=sum[i-1]+a;
cnt[sum[i]%k]++;//存储相同的余数的区间个数
}
ll res=0;
for(int i=0;i<k;i++)
{
res+=cnt[i]*(cnt[i]-1)/2;//组合数
}
cout<<res+cnt[0];//加上k=0时自身是k倍区间的情况
return 0;
}