题目描述
给定一个长度为 NN 的数列,A_1, A_2, \cdots A_NA1,A2,⋯AN,如果其中一段连续的子序列 A_i,A_i+1, \cdots A_jAi,Ai+1,⋯Aj ( i \leq ji≤j ) 之和是 KK 的倍数,我们就称这个区间 [i, j][i,j] 是 K 倍区间。
你能求出数列中总共有多少个 KK 倍区间吗?
输入描述
第一行包含两个整数 NN 和 KK( 1 \leq N,K \leq 10^51≤N,K≤105 )。
以下 N 行每行包含一个整数 A_iAi ( 1 \leq A_i \leq 10^51≤Ai≤105 )
输出描述
输出一个整数,代表 K 倍区间的数目。
输入输出样例
示例
输入
5 2
1
2
3
4
5
输出
6
//k的倍数==前缀和的相同余数之差的总共情况+前缀和本身的情况.
//思路:前缀和+余数相等,前缀余数相等时,相减前缀就能得到有效的k倍区间
//(因为他们余数相等,相减的时候恰好将他们的余数消去可以把前缀比作
//nk+mod,mod是/k后留下的余数,nk1+mod-(nk2+mod),相减就只留下k。
#include <iostream>
using namespace std;
int main()
{
int n,k,a;
cin>>n>>k;
long long sum=0,ans=0;
//当前前缀和 总共情况
int mod[100000];//统计余数相同时的次数
mod[0]=1;//初始化余数为0时余数记为1是因为余数为0时
//自己本身这个区间也算k的倍数,所以要多1,本身这种情况只有1次
//所以只加1,而后与其他余数相同,余数==0时前缀和相减也是一种情况.
for(int i=1;i<n;i++)
{
mod[i]=0;
}//自身情况不算所以初始值为0
for(int i=0;i<n;i++)
{
cin>>a;
sum+=a;//每次都扩大1次前缀
ans+=mod[sum%k];
//对前缀取余,加上前面相同余数的情况,
//相当于直接得到相减的步骤,
//即当前的前缀减去前面所有相同余数前缀的结果
//这里都是前缀相减的结果,不包含自身前缀本身
//只有mod[0]时才是自身情况也算上
mod[sum%k]++;
//加上这一次的前缀的余数情况.
}
cout<<ans;//记得输出结果,调试如果只是答案错误但是什么输出都没有就表示你没打印结果!
//一定要注意,不然白做!
return 0;
}
//取余+相减==k的倍数,所以倍数题目一般都用取余
//如果不清楚自己的结论是否正确,可以自己写测试数据检测一下或者
//列举简单的数字看看结果是否相符,来判断是否程序正确或健全.