1. 程式人生 > >[BZOJ2962][清華集訓]序列操作

[BZOJ2962][清華集訓]序列操作

有一個 mod www. mar CP += 一點 奇數 ons

bzoj
luogu

題意

有一個長度為\(n\) 的序列,有三個操作:
\(I \ \ a\ b\ c\ :\)表示將\([a,b]\)這一段區間的元素集體增加\(c\)
\(R \ \ a\ b\ :\)表示將\([a,b]\)區間內所有元素變成相反數;
\(Q \ \ a\ b\ c\ :\)表示詢問\([a,b]\)這一段區間中選擇\(c\) 個數相乘的所有方案的和\(mod19940417\)的值。
對於100%的數據,\(n≤50000,q≤50000\),初始序列的元素的絕對值\(≤10^9\),保證\([a,b]\)是一個合法區間,\(I\)操作中\(|c|\le10^9\)\(Q\)操作中\(1≤c≤min?(b?a+1,20)\)

sol

維護的信息就是在每一個區間內選出\(0...20\)個數的乘積之和吧。
向上合並就是一個類似卷積的形式,直接\(O(c^2)\)轉移即可。
區間取反簡單一些,就是把所有\(i\)為奇數的信息取反即可。
加一個數相對來說復雜一點,可以把原來的式子大力展開,得到了一個組合數乘\(x\)的若幹次冪之和的形式。
記得處理兩種標記合並的問題。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while
((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 5e4+5; const int mod = 19940417
; struct Data{int f[21];}t[N<<2]; int n,m,C[N][21],tag[N<<2],rev[N<<2]; inline Data operator + (Data a,Data b) { Data c; for (int i=0;i<=20;++i) { c.f[i]=0; for (int j=0;j<=i;++j) (c.f[i]+=1ll*a.f[j]*b.f[i-j]%mod)%=mod; } return c; } void build(int x,int l,int r) { if (l==r) {t[x].f[0]=1;t[x].f[1]=(gi()%mod+mod)%mod;return;} int mid=l+r>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); t[x]=t[x<<1]+t[x<<1|1]; } inline void cover(int x,int l,int r,int v) { Data a;a.f[0]=1; for (int i=1;i<=20;++i) { int w=1;a.f[i]=0; for (int j=i;~j;--j,w=1ll*w*v%mod) (a.f[i]+=1ll*t[x].f[j]*C[r-l+1-j][i-j]%mod*w%mod)%=mod; } t[x]=a;(tag[x]+=v)%=mod; } inline void reverse(int x) { for (int i=1;i<=20;i+=2) t[x].f[i]=mod-t[x].f[i]; rev[x]^=1;tag[x]=mod-tag[x]; } inline void pushdown(int x,int l,int r) { if (rev[x]) { reverse(x<<1);reverse(x<<1|1); rev[x]^=1; } if (tag[x]) { int mid=l+r>>1; cover(x<<1,l,mid,tag[x]);cover(x<<1|1,mid+1,r,tag[x]); tag[x]=0; } } void modify_tag(int x,int l,int r,int ql,int qr,int v) { if (l>=ql&&r<=qr) {cover(x,l,r,v);return;} pushdown(x,l,r);int mid=l+r>>1; if (ql<=mid) modify_tag(x<<1,l,mid,ql,qr,v); if (qr>mid) modify_tag(x<<1|1,mid+1,r,ql,qr,v); t[x]=t[x<<1]+t[x<<1|1]; } void modify_rev(int x,int l,int r,int ql,int qr) { if (l>=ql&&r<=qr) {reverse(x);return;} pushdown(x,l,r);int mid=l+r>>1; if (ql<=mid) modify_rev(x<<1,l,mid,ql,qr); if (qr>mid) modify_rev(x<<1|1,mid+1,r,ql,qr); t[x]=t[x<<1]+t[x<<1|1]; } Data query(int x,int l,int r,int ql,int qr) { if (l>=ql&&r<=qr) return t[x]; pushdown(x,l,r);int mid=l+r>>1; if (qr<=mid) return query(x<<1,l,mid,ql,qr); if (ql>mid) return query(x<<1|1,mid+1,r,ql,qr); return query(x<<1,l,mid,ql,qr)+query(x<<1|1,mid+1,r,ql,qr); } int main() { n=gi();m=gi();C[0][0]=1; for (int i=1;i<=n;++i) { C[i][0]=1; for (int j=1;j<=min(i,20);++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod; } build(1,1,n); while (m--) { char ch=getchar(); while (ch!='I'&&ch!='R'&&ch!='Q') ch=getchar(); int l=gi(),r=gi(),c;if (ch!='R') c=(gi()%mod+mod)%mod; if (ch=='I') modify_tag(1,1,n,l,r,c); if (ch=='R') modify_rev(1,1,n,l,r); if (ch=='Q') printf("%d\n",query(1,1,n,l,r).f[c]); } return 0; }

[BZOJ2962][清華集訓]序列操作