Prefix Sum 牛客网多校

https://www.nowcoder.com/acm/contest/147/H

分块法真的奇妙 更新操作够2000次就n*k的统一更新一次 期间所有更新存起来 有查询了先把之前已经更新好的数组里的内容取出来 然后把存起来还没更新的操作算一遍即可

正解线段树或树状数组

线段树迷之T

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll M=1000000007;

struct node
{
    int x;
    ll y;
};

node order[100010];
ll a[50][100010];
ll pre[200010],ni[200010];
int n,q,k,cnt;

ll quickpow(ll a,ll b)//
{
    ll res;
    res=1;
    while(b>0)
    {
        if(b%2) res=(res*a)%M;
        a=(a*a)%M,b/=2;
    }
    return res;
}

void init()//
{
    ll i;
    pre[0]=1,ni[0]=1;
    for(i=1;i<=200000;i++)
    {
        pre[i]=(pre[i-1]*i)%M;
        ni[i]=quickpow(pre[i],M-2);
    }
}

ll getck(int nn,int kk)//
{
    if(nn<kk) return 0;
    return (pre[nn]*ni[kk]%M)*ni[nn-kk]%M;
}

void force()
{
    int i,j;
    for(i=1;i<=2000;i++) a[0][order[i].x]=(a[0][order[i].x]+order[i].y)%M;
    for(i=1;i<=k;i++)
    {
        for(j=1;j<=n;j++)
        {
            a[i][j]=(a[i-1][j]+a[i][j-1])%M;
        }
    }
}

int main()
{
    ll y,ans;
    int i,op,x;
    init();
    while(scanf("%d%d%d",&n,&q,&k)!=EOF)
    {
        memset(a,0,sizeof(a));
        cnt=0;
        while(q--)
        {
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d%lld",&x,&y);
                cnt++;
                order[cnt].x=x,order[cnt].y=y;
                if(cnt==2000)
                {
                    force();
                    cnt=0;
                }
            }
            else
            {
                scanf("%d",&x);
                ans=a[k][x];
                for(i=1;i<=cnt;i++)
                {
                    if(order[i].x>x) continue;
                    ans=(ans+(getck(k+x-order[i].x-1,k-1)*order[i].y)%M)%M;
                    //ans=(ans+getck(x-order[i].x+k,x-order[i].x))%M;
                }
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sunyutian1998/article/details/81812408