题目大意:给定一个序列,给定一个长度为n的序列,维护三种操作:
区间加
区间变为相反数
求某个区间内任取c个不同的数乘积的所有方案之和对P的模
比如说a b c三个数中取两个 就是ab+ac+bc
这题显然是用线段树来维护下- -
我们用一个0~20的数组a来记录某个区间的信息,其中a[i]表示区间内取i个数的乘积之和
区间合并就是a[i]=Σb[j]*c[i-j] 这个很好理解
区间变为相反数就是把a[1],a[3],a[5],...,a[19]都取反
区间加有点麻烦 就是把a*b*c变成(a+x)*(b+x)*(c+x) 然后把这个式子展开得到a‘[i]=Σa[i-j]*(x^j)*C(len-i+j,j)
其中len是区间长度
然后就可以了 时间复杂度O(nlognc^2)
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 #define MOD 19940417 using namespace std; int C[M][25]; struct abcd{ int a[21],size; //a[i]表示此区间内选i个数乘积之和 abcd() { memset(a,0,sizeof a);size=0; } abcd(int x) { size=1;a[0]=1;a[1]=x; } int& operator [] (int x) { return a[x]; } friend abcd operator + (abcd x,abcd y) { int i,j;abcd re; for(i=0;i<=20;i++) for(j=0;j<=i;j++) (re[i]+=(long long)x[j]*y[i-j]%MOD)%=MOD; re.size=x.size+y.size; return re; } void operator += (int x) { int i,j,temp=x; for(i=20;~i;i--,temp=x) for(j=1;j<=i;j++,temp=(long long)temp*x%MOD) (a[i]+=(long long)a[i-j]*temp%MOD*C[size-i+j][j]%MOD)%=MOD; } void Negate() { int i; for(i=1;i<=20;i+=2) a[i]=(MOD-a[i])%MOD; } }; struct Segtree{ Segtree *ls,*rs; abcd val; int add_mark; bool neg_mark; Segtree() { ls=rs=0x0; add_mark=0; neg_mark=false; } void Build_Tree(int x,int y,int a[]) { int mid=x+y>>1; if(x==y) { new(&val)abcd(a[mid]); return ; } (ls=new Segtree)->Build_Tree(x,mid,a); (rs=new Segtree)->Build_Tree(mid+1,y,a); val=ls->val+rs->val; } void Add(int x) { (add_mark+=x)%=MOD; val+=x; } void Negate() { add_mark=(MOD-add_mark)%MOD; neg_mark^=1; val.Negate(); } void Push_Down() { if(neg_mark) { ls->Negate(); rs->Negate(); neg_mark=false; } if(add_mark) { ls->Add(add_mark); rs->Add(add_mark); add_mark=0; } } void Add(int x,int y,int l,int r,int val) { int mid=x+y>>1; if(l==x&&y==r) { Add(val); return ; } Push_Down(); if(r<=mid) ls->Add(x,mid,l,r,val); else if(l>mid) rs->Add(mid+1,y,l,r,val); else ls->Add(x,mid,l,mid,val) , rs->Add(mid+1,y,mid+1,r,val); this->val=ls->val+rs->val; } void Negate(int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) { Negate(); return ; } Push_Down(); if(r<=mid) ls->Negate(x,mid,l,r); else if(l>mid) rs->Negate(mid+1,y,l,r); else ls->Negate(x,mid,l,mid) , rs->Negate(mid+1,y,mid+1,r); this->val=ls->val+rs->val; } abcd Get_Ans(int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return val; Push_Down(); if(r<=mid) return ls->Get_Ans(x,mid,l,r); if(l>mid) return rs->Get_Ans(mid+1,y,l,r); return ls->Get_Ans(x,mid,l,mid) + rs->Get_Ans(mid+1,y,mid+1,r); } }tree; int n,q; void Pretreatment() { int i,j; for(i=0;i<=n;i++) for(C[i][0]=1,j=1;j<=i&&j<=20;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD; } int main() { int i,x,y,z; cin>>n>>q; char p[10]; Pretreatment(); static int a[M]; for(i=1;i<=n;i++) scanf("%d",&a[i]),a[i]=(a[i]%MOD+MOD)%MOD; tree.Build_Tree(1,n,a); for(i=1;i<=q;i++) { scanf("%s%d%d",p,&x,&y); if(p[0]=='I') scanf("%d",&z),z=(z%MOD+MOD)%MOD,tree.Add(1,n,x,y,z); else if(p[0]=='R') tree.Negate(1,n,x,y); else scanf("%d",&z),printf("%d\n",tree.Get_Ans(1,n,x,y)[z]); } return 0; }
原文地址:http://blog.csdn.net/popoqqq/article/details/43987881