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\n", ans[v]);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/cjoieryl/p/8619922.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值