P4247 [清华集训2012]序列操作
题传
调了一天终于过了,写篇题解庆祝
前两个操作是个 板子,我们考虑操作 3。
注意到
显然有
考虑加上操作 1 怎么做,方案中原本的一个和大概长这个样子:
每个数都加上一个
类似于二项式定理,将其拆解:
不难发现括号里面那堆东西就是旧的
也是暴力合并。
对于操作二,直接将奇数个相乘的、以及加法标记取反即可。
注意要先下传乘法标记。
时间复杂度
Code:
#include <stdio.h>
#include <algorithm>
#include <string.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int mo=19940417;
const int R=20;
inline int read(){
char ch=getchar();int x=0, f=1;
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;
}
inline int mod(int x){return (x%mo+mo)%mo;}
namespace Solution{
const int N=5e4+5;
int n, m, a[N], C[N][25];
struct node{
node(){at=mt=len=0, f[0]=1;for(int i=1; i<=20; i++) f[i]=0;}
int f[25], len;
int at, mt;
}S;
node add(node l, node r){
node c=S;
c.len=l.len+r.len;
for(int i=1; i<=min(R, c.len); i++)
for(int j=0; j<=i; j++)
c.f[i]=mod(c.f[i]+1ll*l.f[j]*r.f[i-j]%mo);
return c;
}
node d[N*30];
struct SegmentTree{
#define ls k<<1
#define rs k<<1|1
#define mid (l+r>>1)
void upd1(int k, int v){//区间加
int t=min(R, d[k].len);
for(int i=t; i; i--)
for(int j=1, st=v; j<=i; j++, st=1ll*st*v%mo)
d[k].f[i]=mod(d[k].f[i]+1ll*d[k].f[i-j]*st%mo*C[d[k].len-i+j][j]%mo);
d[k].at=mod(d[k].at+v);
}
void upd2(int k){//区间取反
int t=min(R, d[k].len);
for(int i=1; i<=t; i++)
if(i&1) d[k].f[i]=mod(-d[k].f[i]);
d[k].at=mod(-d[k].at);
d[k].mt^=1;
}
void pushdown(int k){
if(d[k].mt) upd2(ls), upd2(rs);
if(d[k].at) upd1(ls, d[k].at), upd1(rs, d[k].at);
d[k].at=0, d[k].mt=0;
return ;
}
void build(int k, int l, int r){
d[k]=S;d[k].len=r-l+1;
if(l==r){d[k].f[1]=a[l&r];return ;}
build(ls, l, mid), build(rs, mid+1, r);
d[k]=add(d[ls], d[rs]);
}
void change(int k, int l, int r, int x, int y, int v, bool flg){
// if(flg) printf(">>%d %d\n", k, v);
if(x<=l&&r<=y) return flg?upd1(k, v):upd2(k);pushdown(k);
if(x<=mid) change(ls, l, mid, x, y, v, flg);
if(mid<y) change(rs, mid+1, r, x, y, v, flg);
d[k]=add(d[ls], d[rs]);
}
node query(int k, int l, int r, int x, int y){
if(x<=l&&r<=y) return d[k];pushdown(k);
if(y<=mid) return query(ls, l, mid, x, y);
if(x>mid) return query(rs, mid+1, r, x, y);
return add(query(ls, l, mid, x, y), query(rs, mid+1, r, x, y));
}
void debug(){
for(int j=1; j<=n; j++) printf("---%d",d[1].f[j]);puts("");
}
#undef ls
#undef rs
#undef mid
}Chtholly;
signed work(){
n=read(), m=read();
for(int i=0; i<=20; i++){
C[i][0]=1;
for(int j=1; j<=i; j++)
C[i][j]=mod(C[i-1][j]+C[i-1][j-1]);
}
for(int i=21; i<=n; i++){
C[i][0]=1;
for(int j=1; j<=20; j++)
C[i][j]=mod(C[i-1][j]+C[i-1][j-1]);
}
for(int i=1; i<=n; i++)
a[i]=mod(read());
Chtholly.build(1, 1, n);//Chtholly.debug();
for(int i=1; i<=m; i++){
char opt=getchar();
int a, b, c;
while(opt!='I'&&opt!='R'&&opt!='Q') opt=getchar();
if(opt=='I')
a=read(), b=read(), c=mod(read()), Chtholly.change(1, 1, n, a, b, c, 1);
else if(opt=='R')
a=read(), b=read(), Chtholly.change(1, 1, n, a, b, 0, 0);
else
a=read(), b=read(), c=read(),
printf("%d\n", Chtholly.query(1, 1, n, a, b).f[c]);
//Chtholly.debug();
}
return 0;
}
}
signed main(){
Solution :: work();
return 0;
}