牛牛的等差数列(树状数组,区间加等差数列、区间求和)

https://ac.nowcoder.com/acm/contest/5157/C

区间加等差数列,区间求和

image

树状数组,二阶差分

\(b_i = a_i-a_{i-1}\)

\(c_i=b_i-b_{i-1}\)

\[\sum_{i=1}^n a_i = \sum_{i=1}^n \sum_{j=1}^i b_j = \sum_{i=1}^n \sum_{j=1}^i \sum_{k=1}^j c_k \\= \sum_{k=1}^n c_k \sum_{i,j}[k\le j\le i\le n] = \sum_{k=1}^n c_k \frac{(1+n-k+1)(n-k+1)}{2} \\= \frac12 \times \left [(n+1)(n+2)\sum_{k=1}^n c_k - (2n+3)\sum_{k=1}^n kc_k + \sum_{k=1}^n k^2c_k \right] \]

在原数组 \(a[]\)\([l,r]\) 区间加一个首项为 \(a_0\) 公差为 \(d\) 的等差数列

就是 b[l] += a0, b[l+1~r] += d, b[r+1] -= a0 + d(n-1)

就是 c[l] += a0, c[l+1] += d-a0, c[r+1] -= a0+d*n, c[r+2] += a0+d(n-1)

关于取模:取所有可能的模数的乘积作为模数。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int P = 3*5*7*11*13*17*19*23;
const int inv2 = 55773218; //2的逆,我本地暴力找的

struct BIT {
    int n; vector<ll> tr;
    BIT(int n): n(n), tr(n + 1) {}
    int lowbit(int x) { return x & -x; }
    void add(int p, ll x) { for (; p <= n; p += lowbit(p)) (tr[p] += x) %= P; }
    ll ask(int p) { ll s = 0; for (; p > 0; p -= lowbit(p)) s += tr[p]; return s % P; }
};

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    int n;
    cin >> n;
    
    BIT c(n), kc(n), kkc(n);
    auto add = [&](int p, ll x) { //对c数组的单点加
        c.add(p, x); kc.add(p, x * p % P); kkc.add(p, x * p % P * p % P);
    };
    auto upd = [&](int l, int r, ll a, ll d) { //a数组区间加等差数列
        add(l, a);
        add(l + 1, d - a);
        add(r + 1, -(a + d * (r - l + 1) % P));
        add(r + 2, (a + d * (r - l)) % P);
    };
    auto ask = [&](int n) {
        ll s = c.ask(n) * (n + 1) % P * (n + 2) % P;
        s -= (2 * n + 3) * kc.ask(n) % P;
        s += kkc.ask(n);
        return s % P * inv2 % P;
    };
    
    for (int i = 1; i <= n; i++) {
        int x; cin >> x;
        upd(i, i, x, 0);
    }
    
    int q;
    cin >> q;
    while (q--) {
        int o, l, r, a, d, m;
        cin >> o;
        if (o == 1) {
            cin >> l >> r >> a >> d;
            upd(l, r, a, d);
        } else {
            cin >> l >> r >> m;
            ll ans = (ask(r) - ask(l - 1)) % m;
            cout << (ans + m) % m << '\n';
        }
    }
    
    return 0;
}

posted @ 2024-02-07 13:49  Bellala  阅读(174)  评论(0编辑  收藏  举报