题目描述
思路
通过前缀和计算一个区间的累加和
区间[l, r]
的累加和是前缀和数组sum[r]-sum[l-1]
如果这里暴力枚举区间端点,必定超时,于是想到:如果两个数ab之差(a-b)%k = 0
,意味着 a%k = b%k
,这就好办了
- 开一个数组cnt记录,
cnt[i]
表示前缀和数组中,余数为i
的sum[某个下标]
有多少个 - 然后不断枚举右端点,查询cnt数组中,与右端点同余的端点数目有多少,那么他们就可以和这个新的右端点组成
cnt[sum[i]]
个新区间,答案+=新区间数 - 然后更新cnt数组,把当前右端点的%k对应的数目++,即
cnt[sum[i]%k]
- 最后别忘了加上
cnt[0]
,因为刚好整除k的点,自己成一个长度为1
的区间,而这样的区间有cnt[0]
个
代码
这题想法不难,主要是优化的时候,同余能否想到,这样使得代码的复杂度变为O(n)
还有,注意用 long long ,读取用scanf
加速
#include <bits/stdc++.h>
using namespace std;
#define maxlen 100009
typedef long long ll;
ll a[maxlen];
ll cnt[maxlen] = {0};
int main()
{
int n, k;
cin>>n>>k;
a[0] = 0;
ll ans = 0;
for(int i=1; i<=n; i++)
{
scanf("%ld", &a[i]);
a[i] += a[i-1];
ans += cnt[a[i]%k];
cnt[a[i]%k]++;
}
cout<<ans+cnt[0]<<endl;
return 0;
}