看这数据范围,我还以为是分块……分完了块发现复杂度n根号n*400根本过不了,然后发现根本不用分块,直接线段树就行了
每个区间维护c=0到20的时候的答案,认为当c=0时答案为1
合并两个区间的时候就枚举左边选i个右边选j个,乘起来加到选i+j的答案上去,类似卷积
考虑如何打两个修改操作的标记
首先说翻转操作,把所有c为奇数的答案取反,把加标记取反,就可以了,下传的时候先传翻转再传加
然后考虑加操作,假设把一个长度为len的区间加a
先考虑c得2的情况
对c得3的情况做类似推导,最终得到
可以看出,设si为c得i时的答案的话则
然后就可以线段树搞了,复杂度n logn *400
注意这个模TM不是个质数……所以必须要递推求组合数,由于我们要求的组合数的上标不会超过20,所以还是可以求的
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 50010
#define INF 1000000000
#define MOD 19940417
#define eps 1e-8
#define ll long long
int n,m;
ll s[MAXN<<2][21],ch[MAXN<<2];
bool rev[MAXN<<2];
ll S[21];
ll ST[21];
int a[MAXN];
ll C[MAXN][21];
inline void toch(int x,int y,int z,int cv){
int i,j;
ll now=0;
memcpy(ST,s[x],sizeof(ST));
for(i=1;i<=min(z-y+1,20);i++){
ll cvmi=cv;
for(j=1;j<=i;j++){
(ST[i]+=(C[z-y+1-(i-j)][j]*s[x][i-j])%MOD*cvmi)%=MOD;
(cvmi*=cv)%=MOD;
}
}
memcpy(s[x],ST,sizeof(s[x]));
(ch[x]+=cv+MOD)%=MOD;
}
inline void torev(int x){
int i;
for(i=1;i<=20;i+=2){
(s[x][i]=MOD-s[x][i])%MOD;
}
ch[x]=(MOD-ch[x])%MOD;
rev[x]^=1;
}
inline void pd(int x,int y,int z){
if(rev[x]){
torev(x<<1);
torev(x<<1|1);
rev[x]=0;
}
if(ch[x]){
int mid=y+z>>1;
toch(x<<1,y,mid,ch[x]);
toch(x<<1|1,mid+1,z,ch[x]);
ch[x]=0;
}
}
inline void ud(int x){
int i,j;
memset(s[x],0,sizeof(s[x]));
for(i=0;i<=20;i++){
for(j=0;i+j<=20;j++){
(s[x][i+j]+=s[x<<1][i]*s[x<<1|1][j])%=MOD;
}
}
}
void change1(int x,int y,int z,int l,int r,int cv){
if(y==l&&z==r){
toch(x,y,z,cv);
return ;
}
pd(x,y,z);
int mid=y+z>>1;
if(r<=mid){
change1(x<<1,y,mid,l,r,cv);
}else if(l>mid){
change1(x<<1|1,mid+1,z,l,r,cv);
}else{
change1(x<<1,y,mid,l,mid,cv);
change1(x<<1|1,mid+1,z,mid+1,r,cv);
}
ud(x);
}
void change2(int x,int y,int z,int l,int r){
if(y==l&&z==r){
torev(x);
return ;
}
pd(x,y,z);
int mid=y+z>>1;
if(r<=mid){
change2(x<<1,y,mid,l,r);
}else if(l>mid){
change2(x<<1|1,mid+1,z,l,r);
}else{
change2(x<<1,y,mid,l,mid);
change2(x<<1|1,mid+1,z,mid+1,r);
}
ud(x);
}
void ask(int x,int y,int z,int l,int r){
if(y==l&&z==r){
int i,j;
memset(ST,0,sizeof(ST));
for(i=0;i<=20;i++){
for(j=0;i+j<=20;j++){
(ST[i+j]+=s[x][i]*S[j])%=MOD;
}
}
memcpy(S,ST,sizeof(S));
return ;
}
pd(x,y,z);
int mid=y+z>>1;
if(r<=mid){
ask(x<<1,y,mid,l,r);
}else if(l>mid){
ask(x<<1|1,mid+1,z,l,r);
}else{
ask(x<<1,y,mid,l,mid);
ask(x<<1|1,mid+1,z,mid+1,r);
}
}
void build(int x,int y,int z){
if(y==z){
s[x][0]=1;
s[x][1]=a[y];
return ;
}
int mid=y+z>>1;
build(x<<1,y,mid);
build(x<<1|1,mid+1,z);
ud(x);
int i;
}
int main(){
/*
freopen("data.txt","r",stdin);
freopen("dui.txt","w",stdout);
//*/
int i,j,x,y,z;
char o[20];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
}
C[0][0]=1;
for(i=1;i<=n;i++){
C[i][0]=1;
for(j=1;j<=20;j++){
C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD;
}
}
build(1,1,n);
while(m--){
scanf("%s",o);
if(o[0]=='I'){
scanf("%d%d%d",&x,&y,&z);
change1(1,1,n,x,y,z);
}
if(o[0]=='R'){
scanf("%d%d",&x,&y);
change2(1,1,n,x,y);
}
if(o[0]=='Q'){
scanf("%d%d%d",&x,&y,&z);
memset(S,0,sizeof(S));
S[0]=1;
ask(1,1,n,x,y);
printf("%lld\n",S[z]);
}
}
return 0;
}
/*
3 5
4 5 2
I 1 3 3
R 1 3
Q 1 2 2
*/