这个题卡常数。。
首先c比较小,所以可以考虑dp转移,对于合并子序列就直接枚举跨区间的就可以了
对于反转操作,要注意只有奇数位置才会变成相反数
对于增加操作,可以考虑抽象成组合数学问题:
对于(a1+b)*(a2+b)+(a1+b)*(a3+b)+(a2+b)*(a3+b),拆下来就是每一项都会和不同的两项相乘,
转化到上图上就相当于每组选k个左边的,c-k个右边的,然后组合数学算一下就可以了
码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define P 19940417
#define N 100005
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
int i,j,L[N<<2],R[N<<2],a,b,n,m;
long long lin3[N],lin2[N],lin[N],c,ci[25],ci2[25],jiabj[N<<2],fbj[N<<2],C[N][25],v[N<<2][25];
char op[5];
void up(int o)
{
int ll=o<<1;
int rr=o<<1|1;
for(int i=1;i<=20;i++)
{ v[o][i]=0;
for(int j=0;j<=i;j++)
{
v[o][i]+=(v[ll][j]*v[rr][i-j])%P;
}v[o][i]%=P;
}
}
void jian(int o,int l,int r)
{
L[o]=l;R[o]=r;
v[o][0]=1;
if(l==r)
{
v[o][1]=lin[l];
return;
}
int mid=(l+r)>>1;
jian(zuo);
jian(you);
up(o);
}
void push(int o)
{int i,j;
int ll=o<<1,rr=o<<1|1;
if(fbj[o])
{
fbj[o]=0;
fbj[ll]^=1;
fbj[rr]^=1;jiabj[ll]*=-1,jiabj[rr]*=-1;
for(i=1;i<=20;i++)if(i&1)v[ll][i]*=-1,v[rr][i]*=-1;
}
if(jiabj[o]!=0)
{
for(i=1;i<=20;i++)ci2[i]=(ci2[i-1]*jiabj[o])%P;
for(i=1;i<=20;i++)
for(j=0;j<=i;j++)if(R[ll]-L[ll]+1-j>=0)lin[i]=(lin[i]+v[ll][j]*C[R[ll]-L[ll]+1-j][i-j]%P*ci2[i-j]%P)%P;
for(i=1;i<=20;i++)v[ll][i]=lin[i],lin[i]=0;
jiabj[ll]+=jiabj[o];
jiabj[ll]%=P;
for(i=1;i<=20;i++)
for(j=0;j<=i;j++)
if(R[rr]-L[rr]+1-j>=0)lin[i]=(lin[i]+v[rr][j]*C[R[rr]-L[rr]+1-j][i-j]%P*ci2[i-j]%P)%P;
for(i=1;i<=20;i++)v[rr][i]=lin[i],lin[i]=0;
jiabj[rr]+=jiabj[o];
jiabj[rr]%=P;
jiabj[o]=0;
}
}
void gai(int o,int l,int r)
{
if(a<=l&&r<=b)
{int i,j;
if(op[0]=='Q')
{
for(i=1;i<=c;i++)
for(j=0;j<=i;j++)
lin2[i]+=v[o][j]*lin3[i-j],lin2[i]%=P;
for(i=1;i<=c;i++)
lin3[i]=lin2[i],lin2[i]=0;
}
if(op[0]=='R')
{
jiabj[o]*=-1;
for(i=1;i<=20;i++)if(i&1)v[o][i]*=-1;
fbj[o]^=1;
}
if(op[0]=='I')
{
for(i=1;i<=20;i++)
for(j=0;j<=i;j++)
if(R[o]-L[o]+1-j>=0)lin[i]=(lin[i]+v[o][j]*C[R[o]-L[o]+1-j][i-j]%P*ci[i-j]%P)%P;
for(i=1;i<=20;i++)v[o][i]=lin[i],lin[i]=0;
jiabj[o]+=c;
jiabj[o]%=P;
}
return ;
}
push(o);
int mid=(l+r)>>1;
if(a<=mid)gai(zuo);
if(b>mid)gai(you);
up(o);
}
long long duru()
{
long long x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{ci2[0]=1;
C[0][0]=1;
scanf("%d%d",&n,&m);
for(j=1;j<=n;j++)
{C[j][0]=1;
for(i=1;i<=20;i++)
C[j][i]=(C[j-1][i-1]+C[j-1][i])%P;
}
for(i=1;i<=n;i++)
{
lin[i]=duru();
}
jian(1,1,n);
memset(lin,0,sizeof(lin));
while(m--)
{
scanf("%s",&op);
if(op[0]=='I')
{
a=duru();b=duru();c=duru();
ci[0]=1;
for(i=1;i<=20;i++)
{
ci[i]=(ci[i-1]*c)%P;
}
gai(1,1,n); for(i=1;i<=20;i++)lin[i]=0;
}
if(op[0]=='R')
{
a=duru();b=duru();
gai(1,1,n);for(i=1;i<=20;i++)lin[i]=0;
}
if(op[0]=='Q')
{
a=duru();b=duru();c=duru();
lin3[0]=lin[0]=1;
gai(1,1,n);
printf("%lld\n",(lin3[c]+P)%P);
for(i=1;i<=20;i++)lin3[i]=lin[i]=0;
}
}
}