k 倍区间
题目描述
给定一个长度为 NNN 的数列,A1,A2,⋯ANA_1,A_2, \cdots A_NA1,A2,⋯AN,如果其中一段连续的子序列 Ai,Ai+1,⋯Aj(i≤j)A_i,A_{i+1}, \cdots A_j(i \le j)Ai,Ai+1,⋯Aj(i≤j) 之和是 KKK 的倍数,我们就称这个区间 [i,j][i,j][i,j] 是 KKK 倍区间。
你能求出数列中总共有多少个 KKK 倍区间吗?
输入格式
第一行包含两个整数 NNN 和 KKK(1≤N,K≤105)(1 \le N,K \le 10^5)(1≤N,K≤105)。
以下 NNN 行每行包含一个整数 AiA_iAi(1≤Ai≤105)(1 \le A_i \le 10^5)(1≤Ai≤105)。
输出格式
输出一个整数,代表 KKK 倍区间的数目。
样例 1
样例输入 1
5 2
1
2
3
4
5
样例输出 1
6
前缀和取余
对于求取在数组子段范围内的累计和,是否可以被取余可以使用前缀和取余的思路;
- 求前缀和过程中,前缀和取余的数字,记录这些余数出现的次数;
- 再求各个余数出现次数的组合数(即余数相同的前缀和构成的区间必定可以被整除);
- 还要考虑单个数可以被整除的情况,他们并不构成区间,所以(
mp[0]=1
要被考虑);
#include<bits/stdc++.h>
using namespace std;
int main(){
ios::sync_with_stdio(false);
cout.tie(NULL);cin.tie(NULL);
int n,k;
cin>>n>>k;
int ans=0;
map<int,int>mp;
mp[0] = 1;
for(size_t i=1;i<=n;i++){
int s;cin>>s;
ans+=s;
mp[ans%k]++;
ans%=k;//不影响ans+s
}
ans= 0;
for(int i=0;i<k;i++){
ans+=(mp[i]-1)*mp[i]/2;
}
cout<<ans<<endl;
return 0;
}