D - Range Add Query Editorial by nok0
この問題の原案者です。この解説では、不変量を用いた簡単な方針を説明します。不変量は ABC で問われることは少ないですが、ARC 以降の ad-hoc な問題で頻出なので、実力を付けたい方はぜひ勉強しましょう。
不変量とは、操作などの変換によって変化しない性質のことです。この不変量として適切なものを見つけられると、とても簡単に問題を解けることがあります。(不変量を見つけることが難しい問題が多く、そこは練習が必要です。)
さて、この問題の解説に移ります。今回の操作によって変化しない量はなんでしょうか。
まず、\(i\bmod K=j\) なる \(X_i\) の総和を \(S_j\) とします。 このとき、連続する \(K\) 個の要素にたいして \(c\) の加算を行う時、\(S_0,S_1,\ldots,S_{K-1}\) それぞれ \(c\) だけ変化することがわかります。すなわち、各 \(j\ (1\leq i \leq K-1)\) にたいして、 \(S_0-S_j\) は変化しません。よってこの量が不変量となります。
最終的に、全ての要素が \(0\) にできるとすると、\(S_0=S_1=\ldots=S_{K-1}=0\) となっています。\(S_0-S_j\) が不変であることから、\(X\) が良い数列であるとき、\(S_0=S_1=\ldots=S_{K-1}\) であることが要請されます。
実は、この条件が \(X\) が良い数列であることの十分条件であることも言えます。証明は簡単なので読者への課題とします。
結局、この問題は各クエリに対して \(S_0=S_1=\ldots=S_{K-1}\) であるかを判定できればよいです。これは、\(A\) を \(i\bmod K\) で分類し、それぞれに対して累積和を求めておけば良いです。
以上より、この問題を \(\mathrm{O}((N+Q)K)\) で解くことができました。
実装例(c++):
#include <bits/stdc++.h>
using namespace std;
#define rep(i, x) for(int i = 0; i < (x); i++)
int main() {
int n, k;
cin >> n >> k;
vector<int> a(n);
rep(i, n) cin >> a[i];
vector<vector<long long>> cum(k, vector<long long>(n + 1));
rep(j, k) {
rep(i, n) {
cum[j][i + 1] = cum[j][i] + (i % k == j ? a[i] : 0);
}
}
auto get = [&](int j, int l, int r) {
return cum[j][r] - cum[j][l];
};
int q;
cin >> q;
while(q--) {
int l, r;
cin >> l >> r, --l;
bool same = 1;
long long val = get(0, l, r);
for(int j = 1; j < k; j++) {
same &= val == get(j, l, r);
}
cout << (same ? "Yes" : "No") << endl;
}
}
posted:
last update: