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

https://www.nowcoder.com/acm/contest/148/D

题意

一个A数组,初始全为0。现有三种操作,1:给区间[L,R]+w;2:把每个位置的元素变为其前缀和;3:求区间[L,R]的和

分析

参考:http://www.cnblogs.com/tetew/p/9504595.html

看到题的时候慌了神,因为1、2操作的可能次数实在太大了,认为是什么巧妙的数据结构。。。

实则是组合数学,脑子不够用啊。

首先我们讨论一下对某个位置的数进行+w的操作后,会对后面有什么影响。

纵列看作是2操作的次数,横排看作位置。45°斜着看,有点像杨辉三角!

于是,如果在(i,j)+w,那么对于位于其右下方的点(x,y)来说,贡献为C(x-i+y-j-1,x-i-1)*w

因为3操作不超过500次,我们记录1和2的操作,对于每次3操作,再O(n)查询。

求区间[L,R]的和时,可以直接solve(x+1,R)-solve(x+1,L-1),solve()是求前面所有的操作1和操作2的贡献,并且要加上这一次的求前缀和的贡献(所以是x+1)。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 200000 + 100;
const int maxm = 200000 + 10;
const int mod = 998244353;
ll fac[maxn],inv[maxn];
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return res;
}
void init(){
   fac[0]=1;
   for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod;
   inv[maxn-1]=qpow(fac[maxn-1],mod-2);
   for(int i=maxn-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(int n,int m){
    if(m>n||m<0) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
struct ND{
    int x,pos,w;
}a[maxn];
int cnt;
ll cal(int x,int y){
    ll res=0;
    for(int i=1;i<=cnt;i++){
        if(a[i].x<=x&&a[i].pos<=y){
            res=(res+C(x-a[i].x+y-a[i].pos-1,x-a[i].x-1)*a[i].w%mod+mod)%mod;
        }
    }
    return res;
}
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
#endif
    init();
    int T;
    int n,m,op,x,y;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        int now=1;
        cnt=0;
        while(m--){
            scanf("%d",&op);
            if(op==1){
                scanf("%d%d%d",&x,&y,&op);
                a[++cnt].x=now-1,a[cnt].pos=x,a[cnt].w=op;
                a[++cnt].x=now-1,a[cnt].pos=y+1,a[cnt].w=-op;
            }else if(op==2){
                now++;
            }else{
                scanf("%d%d",&x,&y);
                ll ans=(cal(now+1,y)-cal(now+1,x-1)+mod)%mod;
                printf("%lld
",ans);
            }
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9563521.html