29.牛客网多校第十场D 组合数+多次前缀和

版权声明:欢迎转载 https://blog.csdn.net/animalcoder/article/details/82504847

29.牛客网多校第十场D 组合数+多次前缀和

题意:n个数,初始值为0,m个操作 n,m<=1e5  操作3次数小于500

操作1:区间l~r+=c

操作2:区间1~n每个数变成前缀和

操作3:查询l~r加法和

 

思路:首先我们强行模拟一下前缀和:

第0次前缀和 a1,    a2         a3            a4

第1次前缀和 a1, a1+a2, a1+a2+a3, a1+a2+a3+a4

第2次前缀和 a1,2a1+a2 3a1+2a2+a3,4a1+3a2+2a3+a4

第3次前缀和 a1,3a1+a2 6a1+3a2+a3,10a1+6a2+3a3+a4

….

只考虑a1的系数会发现1:

1

0

0

0

1

1

1

1

1C(1,1)

2 C(2,1)

3 C(3,1)

4 C(4,1)

1 C(2,2)

3 C(3,2)

6 C(4,2)

10 C(5,2)

由发现1得到发现2

发现2:ay对第k次前缀和第x项的影响:C(k-1+y-x,k-1)

比如a1 k=3 的第4项,10a1=C(4-1+3-1 , 3-1)*a1=C(5,2)a1

发现3:

第二次前缀和的前缀和就等于第三次前缀和里的某一项

遇到操作1:

维护已经前缀和次数tm,位置pos,和值,

像差分数组一样维护差分a[l]+=x,a[r+1]-=x

到时候做一次前缀和便能得出结果tot+1

遇到操作3【L,R】

考虑之前每次操作1的贡献,修改ax 会对ax,ax+1.ax+2…ax+R造成影响

由发现3:这些影响的前缀和就是等于下一次前缀和的ax对aR的影响

由发现2:这个影响的计算O(1)解决

所以我们要多做两次前缀和才能得出答案,这就是tot+2的原因

至此,我们求出了1~R的加法和,要求L~R的就多算一遍1~L-1的就好了

 

#include<bits/stdc++.h>
#define ll long long
const int mod=998244353;
using namespace std;
struct fuck{
    int pos,tm,w;
}a[200005];
ll jc[200005],jv[200005];
ll tot;//操作2次数 
ll cnt;//操作1次数 

ll qmod(ll a,ll b)
{
    ll res=1;while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;b=b>>1;
    }return res;
}
ll getC(ll m,ll n)
{
    return jc[m]*jv[n]%mod*jv[m-n]%mod;
}
ll solve(int R)
{
    ll ans=0;
    for(int i=1;i<=cnt;i++)//修改对R的影响 
    {
        if(R>=a[i].pos)
        (ans+=  a[i].w*getC(R-a[i].pos+tot+2 -a[i].tm-1,tot+2 -a[i].tm-1)    )%=mod;
        //因为要算1~R的前缀和 所以tot+1  
        //因为区间+=c维护的是差分,所以要多求一次前缀和 tot+2 
    }
    return ans;
}
int main()
{
    jc[0]=jv[0]=1;
    for(int i=1;i<=200000;i++)jc[i]=jc[i-1]*i%mod;
    jv[200000]=qmod(jc[200000],mod-2);
    for(int i=199999;i>=1;i--)jv[i]=jv[i+1]*(i+1)%mod;
    //printf("%d\n",getC(7,2));
    int T;scanf("%d",&T);
    while(T--)
    {
        int n,m;scanf("%d %d",&n,&m);int op;cnt=tot=0;
        while(m--)
        {
            scanf("%d",&op);
            if(op==1)
            {
                int l,r,w;
                scanf("%d %d %d",&l,&r,&w);
                a[++cnt].pos=l;a[cnt].tm=tot;a[cnt].w=w%mod;
                a[++cnt].pos=r+1;a[cnt].tm=tot;a[cnt].w=(mod-w)%mod;
            }
            else if(op==2)
                tot++;  
            else
            {
                int l,r;scanf("%d %d",&l,&r);
                printf("%lld\n",(solve(r)-solve(l-1)+mod)%mod); 
            }
        }
    } 
}

猜你喜欢

转载自blog.csdn.net/animalcoder/article/details/82504847