1. 程式人生 > >正睿 2019 省選十連測 Day1 T1 息

正睿 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(nlogn20

20)

#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;
}