[前缀和/数论] 数列

【问题描述】
给你一个长度为N的正整数序列,如果一个连续的子序列,子序列的和能够被K整除,那么就视此子序列合法,求原序列包括多少个合法的连续子序列?
对于一个长度为8的序列,K=4的情况:2, 1, 2, 1, 1, 2, 1, 2 。它的答案为6,子序列是位置1->位置8,2->4,2->7,3->5,4->6,5->7。
【输入格式】
第一行:T,表示数据组数
对于每组数据:
第一行:2个数,K,N
第二行:N个数,表示这个序列
【输出格式】
共T行,每行一个数表示答案
【输入样例】
2
7 3
1 2 3
4 8
2 1 2 1 1 2 1 2
【输出样例】
0
6
【数据规模】
100%数据满足
1<=T<=20
1<=N<=50000
1<=K<=1000000
序列的每个数<=1000000000
30%数据满足
1<=T<=10
1<=N,K<=1000

#include<bits/stdc++.h>
using namespace std;
int a,tot,s[1000005];//s[i]用来存1~m前缀和 mod k余i的个数 
int n,t,k;
long long ans;
int main()
{freopen("seq.in","r",stdin);
 freopen("seq.out","w",stdout);
 scanf("%d",&t);
 for(int iii=1;iii<=t;iii++)
{ans=0,tot=0;
 memset(s,0,sizeof(s));
 s[0]=1;
 scanf("%d%d",&k,&n);
 for(int i=1;i<=n;i++) {scanf("%d",&a);tot=(tot+a)%k;s[tot]++;}//计算s 
 for(int i=0;i<k;i++) if(s[i]) ans+=(s[i]*(s[i]-1)/2);
 //由于两个s[i]代表的i相减为0,两个对应位置间(左开右闭)的序列合法 
 //所以答案为每两个相同的s可确定一个合法答案,n个相同的s确定n*(n-1)/2个合法答案
 //最后把每个s[i]得出的答案相加就是总答案 
 printf("%lld\n",ans);
} 
return 0;    
}

 

posted on 2018-10-24 17:21  Miniweasel  阅读(162)  评论(0编辑  收藏  举报

导航