题意:
给你一个长度为n的序列和一个k,问在这个序列中有多少个连续的子序列之和(区间和)是k的倍数。
这是一道蓝桥杯原题,最开始就想着二重循环去骗分,最后实在不知道咋做了看了y总的视频,我才纠正了以前的一个错误(a-b)%p = a%p-b%p。然后我就恍然大悟了。
思路:
首先肯定是求一个前缀和,然和按照暴力的做法我们应该是枚举区间,但是这里有所不同我们枚举的是右区间。为社么是右区间呢? 暴力的做法我们应该去判断 ( s [ r ] − s [ l − 1 ] ) m o d k = = 0 (s[r]-s[l-1]) \ mod \ k == 0 (s[r]−s[l−1]) mod k==0是否成立。但是我们将上式化简, s [ r ] m o d k = s [ l − 1 ] m o d k s[r] \ mod \ k = s[l-1] \ mod \ k s[r] mod k=s[l−1] mod k是否成立就是了。那么到这里我们就可以看我们如果枚举右端点,我们看在他前面 s [ r ] m o d k s[r] \ mod \ k s[r] mod k 这个数出现了多少次就可了对吧,如果我们枚举左端点就不好去记录右边的模数出现情况。特殊的一点我们s[0] = 0,所以余数为0的个数起始就有一个。
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr)
#define endl "\n"
#define int long long
using namespace std;
const int N = 2e5+10, mod = 1e9+7;
int n, _, r, k;
int arr[N];
int cnt[N];
signed main()
{
IOS;
cout << 0 % 2 << endl;
cin >> n >> k;
for(int i = 1; i <= n; i ++) cin >> arr[i], arr[i] += arr[i-1]; \\计算前缀和
int res= 0;
cnt[0] = 1;\\s[0] = 0
for(int i = 1; i <= n; i ++) \\枚举右端点
{
res += cnt[arr[i] % k];
cnt[arr[i] % k]++;
}
cout << res << endl;
return 0;
}