bzoj 2962: 序列操作
阿新 • • 發佈:2018-07-15
turn 表示 scrip get stdout 線段 cin %s rip 變成 \((a+x)*(b+x)*(c+x)\)
用展開就是:
\(a*b*c+(ab+bc+ac)*x+(a+b+c)*x^2+x^3\)
那麽 \(f[i]\) 修改之後的值就是
\(f[i]=\sum_{j=1}^{i}f[j]*C_{len-j}^{i-j}*x^{i-j}\)
\(len\) 是區間長度,因為這個多項式是有 \(len\) 項的,所以要乘以組合數
Description
有一個長度為n的序列,有三個操作1.I a b c表示將[a,b]這一段區間的元素集體增加c,2.R a b表示將[a,b]區間內所有元素變成相反數,3.Q a b c表示詢問[a,b]這一段區間中選擇c個數相乘的所有方案的和mod 19940417的值。
Solution
註意到 \(c\) 比較小,可以直接維護一個 \(O(20^2)\) 的 \(DP\)
即設 \(f[i]\) 表示選了 \(i\) 個數相乘的方案
用線段樹維護
合並的話就是 \(f[o][i]=\sum_{j=0}^{i} f[ls][j]*f[rs][i-j]\)
考慮修改
加上 \(x\),其實就是把所有的 \(a*b*c\)
用展開就是:
\(a*b*c+(ab+bc+ac)*x+(a+b+c)*x^2+x^3\)
那麽 \(f[i]\) 修改之後的值就是
\(f[i]=\sum_{j=1}^{i}f[j]*C_{len-j}^{i-j}*x^{i-j}\)
\(len\) 是區間長度,因為這個多項式是有 \(len\) 項的,所以要乘以組合數
對於變成相反數的操作,要註意:
不僅維護的值要變,標記也要取反
#include <bits/stdc++.h> #define ls (o<<1) #define rs (o<<1|1) using namespace std; const int N=50010,mod=19940417; inline int gi(){ register int str=0;register char ch=getchar();bool fg=0; while(ch>'9' || ch<'0'){if(ch=='-')fg=1;ch=getchar();} while(ch>='0' && ch<='9')str=(str<<3)+(str<<1)+ch-48,ch=getchar(); return fg?-str:str; } int n,Q,c[N][25],f[25],la[N*4];bool rev[N*4]; struct data{int b[25];data(){memset(b,0,sizeof(b));b[0]=1;}}tr[N*4]; inline void priwork(){ for(int i=0;i<=n;i++){ c[i][0]=1; for(int j=min(20,i);j>=1;j--)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } } inline data merge(data x,data y){ data r; for(int i=1;i<=20;i++) for(int j=0;j<=i;j++) r.b[i]=(r.b[i]+1ll*x.b[j]*y.b[i-j])%mod; return r; } inline void build(int l,int r,int o){ if(l==r){tr[o].b[1]=gi()%mod;return ;} int mid=(l+r)>>1; build(l,mid,ls);build(mid+1,r,rs); tr[o]=merge(tr[ls],tr[rs]); } inline void Rec1(int o,int t,int l,int r){ la[o]=(la[o]+t)%mod; for(int len=r-l+1,i=min(len,20);i>=1;i--){ f[i]=0; for(int j=i,tp=1;j>=0;j--,tp=1ll*tp*t%mod) f[i]=(f[i]+1ll*tr[o].b[j]*c[len-j][i-j]%mod*tp)%mod; } for(int i=min(r-l+1,20);i>=1;i--)tr[o].b[i]=f[i]; } inline void Rec2(int o){ rev[o]^=1;la[o]=(mod-la[o])%mod; for(int i=1;i<=20;i+=2)tr[o].b[i]=(mod-tr[o].b[i])%mod; } inline void pushdown(int o,int l,int r){ if(rev[o])Rec2(ls),Rec2(rs),rev[o]=0; if(la[o]){ int mid=(l+r)>>1; Rec1(ls,la[o],l,mid),Rec1(rs,la[o],mid+1,r),la[o]=0; } } inline void add(int l,int r,int o,int sa,int se,int t){ if(sa<=l && r<=se){Rec1(o,t,l,r);return ;} pushdown(o,l,r); int mid=(l+r)>>1; if(se<=mid)add(l,mid,ls,sa,se,t); else if(sa>mid)add(mid+1,r,rs,sa,se,t); else add(l,mid,ls,sa,mid,t),add(mid+1,r,rs,mid+1,se,t); tr[o]=merge(tr[ls],tr[rs]); } inline void Modify(int l,int r,int o,int sa,int se){ if(sa<=l && r<=se){Rec2(o);return ;} pushdown(o,l,r); int mid=(l+r)>>1; if(se<=mid)Modify(l,mid,ls,sa,se); else if(sa>mid)Modify(mid+1,r,rs,sa,se); else Modify(l,mid,ls,sa,mid),Modify(mid+1,r,rs,mid+1,se); tr[o]=merge(tr[ls],tr[rs]); } inline data qry(int l,int r,int o,int sa,int se){ if(sa<=l && r<=se)return tr[o]; pushdown(o,l,r); int mid=(l+r)>>1;data ret; if(se<=mid)ret=qry(l,mid,ls,sa,se); else if(sa>mid)ret=qry(mid+1,r,rs,sa,se); else ret=merge(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se)); tr[o]=merge(tr[ls],tr[rs]); return ret; } int main() { freopen("pp.in","r",stdin); freopen("pp.out","w",stdout); cin>>n>>Q;priwork(); build(1,n,1); char s[2];int l,r; while(Q--){ scanf("%s%d%d",s,&l,&r); if(s[0]=='I')add(1,n,1,l,r,gi()%mod); else if(s[0]=='R')Modify(1,n,1,l,r); else printf("%d\n",(qry(1,n,1,l,r).b[gi()]+mod)%mod); } return 0; }
bzoj 2962: 序列操作