题目描述
Edward 得到了一个长度为 N 的整数序列,他想找出这里面有多少个“幸运的”连续子序列。一个连续子序列被称为“幸运的”,当且仅当该子序列内的整数之和恰好是 K 的整数倍数。他请求你写一个程序来计算他喜欢的连续子序列个数。
输入
输入第一行是一个整数 T,表示有 T 组数据。
每组数据第一行是两个整数 N (1 <= N <= 10^6 ), K (1 <= K <= 10^9 )。
接下来的一行包含 N 个整数 A i (|A i | <= 10^9 )。
输出
对于每组测试数据,输出一行仅包含一个整数,表示 Edward 喜欢的连续子序列数量。
示例输入
2
5 3
1 2 3 4 1
6 2
1 2 1 2 1 2
示例输出
http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=3173
范围很大不能用O(n2)的做法。这时考虑前缀和同模做差。但是很难想到。
比如,有a b c d e,(a+b)%mod=k,(a+b+c+d+e)%mod也=k,那么(c+d+e)%mod=0,即该子序列是mod的整数倍数。
#include<iostream>
#include<algorithm>
#include<string>
#include<map>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define ll long long
using namespace std;
ll x[1000001];
ll C(ll m,ll n){
ll i,j,sum=1;
for (i=m,j=0;j<n;j++,i--)
sum=sum*i/(j+1);
return sum;
}
int main(){
ll t,n,m;
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
x[0]=0;
ll cnt=0;
ll w;
for(ll i=1;i<=n;++i){
cin>>w;
x[i]=((x[i-1]+w)%m+m)%m; //因为w有可能是负的
}
sort(x,x+n+1);
ll s=1;
for(ll i=1;i<=n;++i){
if(x[i]==x[i-1])
s++;
else{
cnt+=C(s,2);
s=1;
}
}
cnt+=C(s,2);
printf("%lld\n",cnt);
}
return 0;
}