P8649 [蓝桥杯 2017 省 B] k 倍区间
思路
这题很经典,首先用前缀和维护,若区间 [ l , r ] [l,r] [l,r]符合条件,则 s l − 1 ≡ s r ( m o d k ) s_{l-1}\equiv s_r(mod k) sl−1≡sr(modk),故对于前缀和的余数,若某个余数出现了 x x x次,则可在这 x x x个坐标中任选两个作为边界即可,即为 C x 2 C_{x}^{2} Cx2,若余数为零,则单个数也符合,最后在加上去
代码
#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;
int cnt = 0;
for(int i = 1;i <= n;i++)
{
int x;
cin >> x;
ans += (x % k); //计算前缀和
mp[ans % k]++; //前缀和模 k
ans %= k;
}
for(int i = 0;i < k;i++) cnt += (mp[i] * (mp[i] - 1)) / 2; //根据上述公式计算答案
cout << cnt + mp[0] << endl; //将单个的加上去
return 0;
}