K倍区间
题目链接
给定一个长度为 N 的数列,A1,A2,…AN,如果其中一段连续的子序列 Ai,Ai+1,…Aj 之和是 K 的倍数,我们就称这个区间 [i,j] 是 K 倍区间。
你能求出数列中总共有多少个 K 倍区间吗?
输入格式
第一行包含两个整数 N 和 K。
以下 N 行每行包含一个整数 Ai。
输出格式
输出一个整数,代表 K 倍区间的数目。
数据范围
1≤N,K≤100000,
1≤Ai≤100000
输入样例:
5 2
1
2
3
4
5
输出样例:
6
算法分析
区间和要用到前缀和,我们要求的是区间和[l,r]就是he[r]-he[l-1]
(he[r]-he[l-1])%k= = 0 就符合,那我们模拟l和r的过程是O(n2)的级别肯定是过不了的,这里有个技巧(he[r]-he[l-1]) % k= =0相当于
he[r]%k==he[l-1]%k,所以只要一个区间的前缀和取余相等那么就可以有一个组合。在考虑子序列贡献了多少次就可以了
代码实现
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+5;
typedef long long ll;
ll a[maxn];
ll he[maxn];
ll cnt[maxn];
int main()
{
ll k,n;
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++)
{
he[i]=he[i-1]+a[i];
}
ll res=0;
cnt[0]++;
for(int i=1;i<=n;i++)
{
res+=cnt[he[i]%k];//子序列贡献这么多
cnt[he[i]%k]++;
}
cout<<res<<endl;
}