牛客网暑期ACM多校训练营(第十场)D Rikka with Prefix Sum [组合数]

版权声明: https://blog.csdn.net/weixin_39792252/article/details/82415291

                                     D Rikka with Prefix Sum

 

题意:给一个数组a,一开始的值全为0,一共有三个操作: 
1. 对区间[L,R]的每个数都加上w。 
2. 将数组a用其前缀和数组代替。 
3. 将询问区间[L,R]的区间和。

假设初始状态是t = 0,每执行一次 2 就t++,这样考虑每个1操作对于后面的影响,考虑是路径的问题,就是组合数。

 代码:

#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <cassert>
#define ll long long
 
using namespace std;
 
const ll maxn = 5e6+7;
const ll mod = 998244353;
 
struct node{
    ll t, where, w;
} A[maxn];
 
int len;
ll F[maxn + 10], inv[maxn + 10];
 
ll qpow(ll a, ll b){
    ll ans = 1ll;
    while(b){
        if(b&1) ans = (ans*a)%mod;
        a = (a*a)%mod;
        b >>= 1;
    }
    return ans;
}
 
void init()
{
    F[0] = 1ll;
    for (ll i = 1; i <= maxn; i++) F[i] = (F[i-1]*i)%mod;
    inv[maxn] = qpow(F[maxn], mod - 2ll); //费马小定理求 N!的逆元
    for(ll i = maxn - 1; i >= 0; i--) inv[i] = (inv[i+1]*(i+1))%mod;
}
 
 
ll C(ll a , ll b){ return F[a]*inv[b]%mod*inv[a-b]%mod; }
 
ll query(ll where,ll t){
    ll ans = 0;
    for (int i = 1; i <= len; i++)
        if (A[i].where <= where) ans = (ans + A[i].w*C(where - A[i].where + t - A[i].t - 1, t - A[i].t - 1))%mod;
    return ans;
}
 
void solve(){
    int n, m;
    scanf("%d%d", &n, &m);
    len = 0;
    ll t = 0, l, r, w;
 
    while(m--){
        int op; scanf("%d", &op);
        if(op == 1){
            scanf("%lld%lld%lld", &l, &r, &w);
            A[++len] = (node){ t-1, l, w };
            A[++len] = (node){ t-1, r+1, (mod-w)%mod };
        } else if (op == 2) t++;
          else{
            scanf("%lld%lld", &l, &r);
            printf("%lld\n",(query(r, t+1) - query(l-1, t+1) + mod)%mod);
        }
    }
}
 
 
 
int main(){
    init();
    //freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while(t--) solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39792252/article/details/82415291