bzoj 2962 序列操作
2962: 序列操作
Time Limit: 50 Sec Memory Limit: 256 MB[Submit][Status][Discuss]
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的值。
Input
第一行两个数n,q表示序列长度和操作个数。
第二行n个非负整数,表示序列。
接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。
Output
对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。
Sample Input
5 5
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1
Sample Output
40
19940397
样例说明
做完第一个操作序列变为1 3 4 4 5。
第一次询问结果为3*4+3*4+4*4=40。
做完R操作变成-1 -3 -4 -4 -5。
做完I操作变为-2 -4 -5 -4 -5。
第二次询问结果为-2-4-5-4-5=-20。
19940397
样例说明
做完第一个操作序列变为1 3 4 4 5。
第一次询问结果为3*4+3*4+4*4=40。
做完R操作变成-1 -3 -4 -4 -5。
做完I操作变为-2 -4 -5 -4 -5。
第二次询问结果为-2-4-5-4-5=-20。
HINT
100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。
Source
我写的题解看这里的T2
http://www.cnblogs.com/TheRoadToTheGold/p/7723564.html
网上的参考题解
http://blog.csdn.net/werkeytom_ftd/article/details/51767696
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; #define N 50001 const int mod=19940417; typedef long long LL; int n; int C[N][21]; int f[N<<2]; int siz[N<<2],mid[N<<2]; bool rev[N<<2]; struct node { int sum[21]; }ans[N<<2]; void read(int &x) { x=0; int ff=1; char c=getchar(); while(!isdigit(c)) { if(c=='-') ff=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=ff; } int tot=0; void MOD(int &a,int b) { a+=b; a-= a>=mod ? mod : 0; } void pre(int n) { 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; } } void update(int k) { for(int i=1;i<=20;i++) { ans[k].sum[i]=0; for(int j=1;j<i;j++) MOD(ans[k].sum[i],1ll*ans[k<<1].sum[j]*ans[k<<1|1].sum[i-j]%mod); MOD(ans[k].sum[i],ans[k<<1].sum[i]); MOD(ans[k].sum[i],ans[k<<1|1].sum[i]); } } void build(int k,int l,int r) { siz[k]=r-l+1; if(l==r) { read(ans[k].sum[1]); MOD(ans[k].sum[1],0); return; } mid[k]=l+r>>1; build(k<<1,l,mid[k]); build(k<<1|1,mid[k]+1,r); update(k); } void insert(int k,int w) { MOD(f[k],w); for(int i=20;i;i--) { int x=w; for(int j=i-1;j;j--,x=1ll*x*w%mod) MOD(ans[k].sum[i],1ll*x*ans[k].sum[j]%mod*C[siz[k]-j][i-j]%mod); MOD(ans[k].sum[i],1ll*x*C[siz[k]][i]%mod); } } void turn(int k) { rev[k]^=1; if(f[k]) f[k]=mod-f[k]; for(int i=19;i>0;i-=2) if(ans[k].sum[i]) ans[k].sum[i]=mod-ans[k].sum[i]; } void down(int k) { if(rev[k]) turn(k<<1),turn(k<<1|1),rev[k]=0; if(f[k]) insert(k<<1,f[k]),insert(k<<1|1,f[k]),f[k]=0; } void add(int k,int l,int r,int opl,int opr,int w) { if(l>=opl && r<=opr) { insert(k,w); return; } down(k); if(opl<=mid[k]) add(k<<1,l,mid[k],opl,opr,w); if(opr>mid[k]) add(k<<1|1,mid[k]+1,r,opl,opr,w); update(k); } void reverse(int k,int l,int r,int opl,int opr) { if(l>=opl && r<=opr) { turn(k); return; } down(k); if(opl<=mid[k]) reverse(k<<1,l,mid[k],opl,opr); if(opr>mid[k]) reverse(k<<1|1,mid[k]+1,r,opl,opr); update(k); } node query(int k,int l,int r,int opl,int opr,int w) { if(l>=opl && r<=opr) return ans[k]; down(k); if(opr<=mid[k]) return query(k<<1,l,mid[k],opl,opr,w); else if(opl>mid[k]) return query(k<<1|1,mid[k]+1,r,opl,opr,w); else { node L=query(k<<1,l,mid[k],opl,opr,w),R=query(k<<1|1,mid[k]+1,r,opl,opr,w); node tmp; for(int i=1;i<=w;i++) { tmp.sum[i]=(L.sum[i]+R.sum[i])%mod; for(int j=1;j<i;j++) MOD(tmp.sum[i],1ll*L.sum[j]*R.sum[i-j]%mod); } return tmp; } } int main() { int n,m; char c[3]; read(n); read(m); pre(n); build(1,1,n); int l,r,w; while(m--) { scanf("%s",c); read(l); read(r); if(c[0]=='I') { read(w); w%=mod; w+= w<0 ? mod : 0; add(1,1,n,l,r,w); } else if(c[0]=='R') reverse(1,1,n,l,r); else { read(w); node p=query(1,1,n,l,r,w); printf("%d\n",query(1,1,n,l,r,w).sum[w]); } } }