Official

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: