正睿 2019 省選十連測 Day1 T1 息
阿新 • • 發佈:2018-12-03
一個顯然的結論是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
#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; }