分析:
线段树维护序列信息,需要注意的几个点:
1、标记的更新顺序:先更新RevTag,再更新AddTag。
2、作区间加法时f[i]=∑(j=0 to i)x^j*f[i-j]*C[len-(i-j)][j],证明有些像二项式定理。
3、pushup()时由于k较小,直接暴力卷积即可,记得先把f数组清零。
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
typedef long long LL;
inline LL read(){
LL 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<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
const int MAXN=50005;
const LL MOD=19940417;
int n,q,ql,qr;
LL c[MAXN][21],seq[MAXN],kk;
struct Node{
LL f[21],atag;
int rtag;
Node(){
memset(f,0,sizeof f);
atag=rtag=0;
}
}a[MAXN<<2];
inline void pre_process(){
c[0][0]=1;
for(int i=1;i<=n;i++)
for(int j=0;j<=20;j++){
c[i][j]=c[i-1][j];
if(j) c[i][j]=(c[i][j]+c[i-1][j-1])%MOD;
}
}
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
#define len (r-l+1)
inline void pushup(int o,int l,int r){
for(int i=0;i<=len&&i<=20;i++){
a[o].f[i]=0;
for(int j=0;j<=((len+1)>>1)&&j<=i;j++)
a[o].f[i]=(a[o].f[i]+a[lc].f[j]*a[rc].f[i-j])%MOD;
}
}
inline void pushr(int o,int l,int r){
for(int i=1;i<=len&&i<=20;i+=2) a[o].f[i]=-a[o].f[i];
a[o].atag=-a[o].atag;
a[o].rtag^=1;
}
inline void pusha(int o,int l,int r,LL kkk){
for(int i=std::min(len,20);i+1;i--){
LL temp=1;
for(int j=0;j<=i;j++){
if(j==0){
temp=temp*kkk%MOD;
continue;
}
a[o].f[i]=(a[o].f[i]+temp*a[o].f[i-j]%MOD*c[len-i+j][j])%MOD;
temp=temp*kkk%MOD;
}
}
a[o].atag=(a[o].atag+kkk)%MOD;
}
inline void pushdown(int o,int l,int r){
if(a[o].rtag){
pushr(lc,l,mid);
pushr(rc,mid+1,r);
a[o].rtag=0;
}
if(a[o].atag){
pusha(lc,l,mid,a[o].atag);
pusha(rc,mid+1,r,a[o].atag);
a[o].atag=0;
}
}
void build(int o,int l,int r){
if(l==r){
a[o].f[0]=1;
a[o].f[1]=seq[l]%MOD;
return;
}
build(lc,l,mid);
build(rc,mid+1,r);
pushup(o,l,r);
// std::cout<<l<<" "<<r<<">>>";
// for(int i=0;i<=20;i++)
// std::cout<<a[o].f[i]<<" ";
// std::cout<<std::endl;
}
void radd(int o,int l,int r){
if(ql<=l&&r<=qr){
pusha(o,l,r,kk);
return;
}
pushdown(o,l,r);
if(mid>=ql) radd(lc,l,mid);
if(mid<qr) radd(rc,mid+1,r);
pushup(o,l,r);
}
void rrev(int o,int l,int r){
if(ql<=l&&r<=qr){
pushr(o,l,r);
return;
}
pushdown(o,l,r);
if(mid>=ql) rrev(lc,l,mid);
if(mid<qr) rrev(rc,mid+1,r);
pushup(o,l,r);
}
Node query(int o,int l,int r){
if(ql<=l&&r<=qr) return a[o];
pushdown(o,l,r);
if(mid<ql) return query(rc,mid+1,r);
else if(mid>=qr) return query(lc,l,mid);
else{
Node ret1=query(lc,l,mid);
Node ret2=query(rc,mid+1,r);
Node ret;
for(int i=0;i<=20;i++)
for(int j=0;j<=i;j++)
ret.f[i]=(ret.f[i]+ret1.f[j]*ret2.f[i-j])%MOD;
return ret;
}
}
#undef mid
#undef lc
#undef rc
#undef len
int main(){
n=read(),q=read();
pre_process();
for(int i=1;i<=n;i++) seq[i]=read();
build(1,1,n);
while(q--){
char opt=getchar();
while(!isalpha(opt)) opt=getchar();
if(opt=='I'){
ql=read(),qr=read(),kk=read();
radd(1,1,n);
}
else if(opt=='R'){
ql=read(),qr=read();
rrev(1,1,n);
}
else{
ql=read(),qr=read();int c=read();
Node ans=query(1,1,n);
printf("%lld\n",(ans.f[c]+MOD)%MOD);
}
}
return 0;
}