[ABC367D] Pedometer-xzy巨佬简洁做法
[ABC367D] Pedometer-xzy巨佬简洁做法
https://www.luogu.com/article/n64n78cs
对照巨佬的代码进一步理解
//徐知鱼
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1;
ch = getchar();
}
while(isdigit(ch)) {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
const int N = 400010,M=1000010;
int n, m, a[N], s[N], t[M];
long long ans;
int main() {
#ifdef LOCAL
freopen("1.txt","r",stdin);
#endif
#ifndef LOCAL
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#endif
n = read(), m = read();
for(int i = 1; i <= n; ++i) a[i] = a[i + n] = read();//复制一遍
for(int i = 1; i <= n * 2-1; ++i) s[i] = (s[i - 1] + a[i]) % m;
//破环为链后的前缀和,s[2n]表示从2n~2n+1,而1一直到n后,n+1就是1了
//所以2n+1最后回到1,就是1->2->3...n-1->n->1'->2'->3'...(n-1)'->n'->1''
for(int i = 1; i <= n * 2-1; ++i) {
if(i > n) --t[s[i - n]];
ans += t[s[i]];
if(i <= n) ++t[s[i]];
}
/*
我们先优先考虑i<=n的情况。
此时,每次加入,实际上就是看和以i+1结尾的同余的位置,我们就处理完了从小编号到大编号的部分。
之后,到了1',删去了s[1],那么就是只有从2~n到1了,就算是处理大编号到小编号的情况。
事实上,到n',就没有贡献了,但是之后也没有贡献,图方便就用2n了。
这里循环的顺序也很有考究。
就是每次插入s[i]是在计算之后,就保证不会自己到自己
而当i=n时,计算的恰好是1~n,s<t 的情况。
之后当i=n+1时,会删去s[1],这样就是2~n过来了。
之后同理,变成2~n以及1'
可以保证答案了。
因此,可以枚举到2n-1,这样是n到(n-1)',枚举到2n,此时t数组为空,计算也无妨。
*/
cout << ans << '\n';
return 0;
}