• Bzoj2962: 序列操作


    题面

    传送门

    Sol

    线段树,维护一个长度为(20)的数组,每次合并时就是左右儿子做个卷积
    区间加法
    二项式展开
    (len)表示区间长度,加的(x)的贡献组合数算一下就好了
    看代码就知道了

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(5e4 + 5);
    const int Zsy(19940417);
    
    IL ll Input(){
        RG ll x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int n, q, c[_][21];
    struct Segment{
        int tag, rev, s[21];
    } T[_ << 2];
    int tmp[21], ans[21];
    
    IL void Update(RG int x){
        RG int ls = x << 1, rs = x << 1 | 1;
        for(RG int i = 0; i <= 20; ++i){
            T[x].s[i] = 0;
            for(RG int j = 0; j <= i; ++j)
                (T[x].s[i] += 1LL * T[ls].s[j] * T[rs].s[i - j] % Zsy) %= Zsy;
        }
    }
    
    IL void Adjust1(RG int x){
        T[x].rev ^= 1, T[x].tag = Zsy - T[x].tag;
        for(RG int i = 1; i < 20; i += 2) T[x].s[i] = Zsy - T[x].s[i];
    }
    
    IL void Adjust2(RG int x, RG int v, RG int l, RG int r){
        (T[x].tag += v) %= Zsy;
        RG int len = r - l + 1;
        for(RG int i = 1; i <= 20; ++i){
            tmp[i] = 0;
            for(RG int j = i, g = 1; ~j; --j, g = 1LL * g * v % Zsy)
                (tmp[i] += 1LL * T[x].s[j] * c[len - j][i - j] % Zsy * g % Zsy) %= Zsy;
        }
        for(RG int i = 1; i <= 20; ++i) T[x].s[i] = tmp[i];
    }
    
    IL void Pushdown(RG int x, RG int l, RG int r){
        if(T[x].rev){
            Adjust1(x << 1), Adjust1(x << 1 | 1);
            T[x].rev ^= 1;
        }
        if(T[x].tag){
            RG int mid = (l + r) >> 1;
            Adjust2(x << 1, T[x].tag, l, mid);
            Adjust2(x << 1 | 1, T[x].tag, mid + 1, r);
            T[x].tag = 0;
        }
    }
    
    IL void Build(RG int x, RG int l, RG int r){
        T[x].s[0] = 1;
        if(l == r){
            T[x].s[1] = (Input() % Zsy + Zsy) % Zsy;
            return;
        }
        RG int mid = (l + r) >> 1;
        Build(x << 1, l, mid), Build(x << 1 | 1, mid + 1, r);
        Update(x);
    }
    
    IL void Modify1(RG int x, RG int l, RG int r, RG int L, RG int R){
        if(L <= l && R >= r){
            Adjust1(x);
            return;
        }
        Pushdown(x, l, r);
        RG int mid = (l + r) >> 1;
        if(L <= mid) Modify1(x << 1, l, mid, L, R);
        if(R > mid) Modify1(x << 1 | 1, mid + 1, r, L, R);
        Update(x);
    }
    
    IL void Modify2(RG int x, RG int l, RG int r, RG int L, RG int R, RG int v){
        if(L <= l && R >= r){
            Adjust2(x, v, l, r);
            return;
        }
        Pushdown(x, l, r);
        RG int mid = (l + r) >> 1;
        if(L <= mid) Modify2(x << 1, l, mid, L, R, v);
        if(R > mid) Modify2(x << 1 | 1, mid + 1, r, L, R, v);
        Update(x);
    }
    
    IL void Calc(RG int x){
        for(RG int i = 1; i <= 20; ++i){
            tmp[i] = 0;
            for(RG int j = 0; j <= i; ++j)
                (tmp[i] += 1LL * ans[j] * T[x].s[i - j] % Zsy) %= Zsy;
        }
        for(RG int i = 1; i <= 20; ++i) ans[i] = tmp[i];
    }
    
    IL void Query(RG int x, RG int l, RG int r, RG int L, RG int R){
        if(L <= l && R >= r){
            Calc(x);
            return;
        }
        Pushdown(x, l, r);
        RG int mid = (l + r) >> 1;
        if(L <= mid) Query(x << 1, l, mid, L, R);
        if(R > mid) Query(x << 1 | 1, mid + 1, r, L, R);
    }
    
    int main(RG int argc, RG char *argv[]){
        n = Input(), q = Input(), c[0][0] = 1;
        for(RG int i = 1; i <= n; ++i){
            c[i][0] = 1;
            for(RG int j = 1; j <= 20; ++j)
                c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % Zsy;
        }
        Build(1, 1, n);
        while(q--){
            RG char op; scanf(" %c", &op);
            RG int l = Input(), r = Input(), v;
            if(op == 'I') v = Input(), Modify2(1, 1, n, l, r, (v % Zsy + Zsy) % Zsy);
            else if(op == 'R') Modify1(1, 1, n, l, r);
            else{
                v = Input(), Fill(ans, 0), ans[0] = 1;
                Query(1, 1, n, l, r);
                printf("%d
    ", ans[v]);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Codevs堆练习
    codevs 3110 二叉堆练习3
    浅谈堆
    codevs 2924 数独挑战
    搜索技巧——持续更新
    2144 砝码称重 2
    codevs 2928 你缺什么
    codevs 2594 解药还是毒药
    codevs 2147 数星星
    判断素数
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8619922.html
Copyright © 2020-2023  润新知