正睿 2019 省选十连测 Day1 T1 息

一个显然的结论是c[j]对f[x][y]的贡献系数为从(1,j)走到(x,y)的方案数。

60pts
发现x很小,考虑用一个大小为20n线段树来维护
区间[l,r]表示l到r中的所有ci对r的贡献值
合并的时候f[l,r,i]=f[mid+1,r,i]+∑f[l,mid,j]
c(i-j+r-(mid+1),i-j);
这个式子的含义:
首先f[mid+1,r,i]的含义很明显
左边考虑去枚举所有最后对r产生贡献的方案在走到mid的时候所处的行
这些显然互斥且可以表示全集
然后每一种走到(j,mid)方案,有c(i-j+r-(mid+1)种方案走到(i,r)//这里第一步强制只能往右走
用线段树维护的复杂度为O(nlogn2020)

#include<iostream>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define K 25
#define N 221000
#define L 220000
#define eps 1e-7
#define inf 1e9+7
#define ll long long
using namespace std;
inline ll read()
{
    char ch=0;
    ll x=0,flag=1;
    while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*flag;
}
const ll mo=1000000007;
ll x,y,c[N][K];
ll exgcd(ll a,ll b)
{
    if(!b)
    {
        x=1;
        y=0;
        return a;
    }
    ll d=exgcd(b,a%b);
    ll t=x;
    x=y;
    y=t-(a/b)*y;
    return d;
}
ll inv(ll o)
{
    exgcd(((o%mo)+mo)%mo,mo);
    return ((x%mo)+mo)%mo;
}
ll n,m,v[N],w[N];
struct node
{
    ll f[K];
};
struct Segment_Tree
{
    #define lson o<<1
    #define rson o<<1|1
    #define mid ((l+r)>>1)
    ll dp[N*4][K];
    inline void pushup(ll o,ll l,ll r)
    {
        for(ll i=1;i<=20;i++)
        {
            dp[o][i]=dp[rson][i];
            for(ll j=1;j<=i;j++)
            dp[o][i]=(dp[o][i]+((dp[lson][j]*c[i-j+r-(mid+1)][i-j])%mo))%mo; 
        }
    }
    void build(ll o,ll l,ll r)
    {
        if(l==r)
        {
            for(ll i=1;i<=20;i++)dp[o][i]=w[l];
            return;
        }
        build(lson,l,mid);
        build(rson,mid+1,r);
        pushup(o,l,r);
    }
    void optset(ll o,ll l,ll r,ll q,ll num)
    {
        if(l==r)
        {
            for(ll i=1;i<=20;i++)dp[o][i]=num;
            return;
        }
        if(q<=mid)optset(lson,l,mid,q,num);
        if(q>mid)optset(rson,mid+1,r,q,num);
        pushup(o,l,r);
    }
    node query(ll o,ll l,ll r,ll ql,ll qr)
    {
        if(ql<=l&&r<=qr)
        {
            node ans;
            for(ll i=1;i<=20;i++)ans.f[i]=dp[o][i];
            return ans;
        }
        bool flag1=false,flag2=false;
        if(ql<=mid)flag1=true;
        if(qr>mid)flag2=true;
        if(flag1&&flag2)
        {
            node a=query(lson,l,mid,ql,qr);
            node b=query(rson,mid+1,r,ql,qr);
            node ans;
            for(ll i=1;i<=20;i++)
            {
                ans.f[i]=b.f[i];
                for(ll j=1;j<=i;j++)
                ans.f[i]=(ans.f[i]+((a.f[j]*c[i-j+qr-(mid+1)][i-j])%mo))%mo; 
            }
            return ans;
        }
        else
        {
            if(flag1)return query(lson,l,mid,ql,qr);
            if(flag2)return query(rson,mid+1,r,ql,qr);
        }
    }
}T;
int main()
{
    ll i,p,k,x,y,flag;
    n=read();m=read();
    for(i=1;i<=L;i++)v[i]=inv(i);
    for(k=0;k<=20;k++)
    {
        c[k][k]=1;
        for(i=k;i<=L;i++)
        c[i+1][k]=(c[i][k]*(((i+1)*v[i-k+1])%mo))%mo;
    }
    for(i=1;i<=n;i++)w[i]=read();
    T.build(1,1,n);
    for(p=1;p<=m;p++)
    {
        flag=read();x=read();y=read();
        if(flag==1)
        {
            T.optset(1,1,n,x,y);
            w[x]=y;
        }
        else
        {
            if(x==0)
            { 
                printf("%lld\n",w[y]);
                continue;
            }
            ll ans=0; 
            node o=T.query(1,1,n,1,y);
            printf("%lld\n",o.f[x]);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Creed-qwq/p/10056441.html