【题解】P8649 题解
P8649 题解
思路分析
一道简单前缀和的题。
首先,看到”连续子序列求和”这一要求时,我们果断选择前缀和解答。
接着我们要分析,什么时候这段区间的和为 的倍数?显然,当区间和 满足 ,即 时,为 的倍数。
而又由于原数组 中 的区间和 等于 ( 为 的前缀和数组),所以 。所以 。
也就是说,我们只需判断前缀和模 是否同余就可以了,但一个个枚举区间有点慢,怎么办呢?
我们可以来一个“回手掏”,从”模 同余“入手。我们可以开一个 map 记录每个前缀和模 的余数出现的次数,然后在同余数的情况下,任选两个前缀和,必然能够构成一段区间,这段区间的和为 的倍数。设某个余数出现了 次,则必会存在 段区间和为 的倍数。
注意:map 要将余数 出现的次数初始化为 。这样的话,如果 出现了 次的话,则必会存在 段区间和为 的倍数。为什么呢?因为,根据题意,一个数也算一段区间,即答案为:
依据上述步骤实现即可,然后记得开 long long。
代码
#include <iostream>
#include <map>
#define int long long
using namespace std;
map <int, int> mp; //记录每个余数出现个数的数组
signed main()
{
int n, k, ans = 0;
cin >> n >> k;
mp[0] = 1; //初始化 0 出现的次数为 1
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
ans += (x % k); //计算前缀和
mp[ans % k]++; //前缀和模 k
ans %= k;
}
int cnt = 0;
for(int i = 0;i < k;i++) cnt += (mp[i] * (mp[i] - 1)) / 2; //根据上述公式计算答案
cout << cnt << endl;
return 0;
}

浙公网安备 33010602011771号