题目大意:给定一个序列,给定一个长度为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;
}