题目大意:有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值
题解:维护取反标记和加标记,取反优先级高于加
对于操作3,每个线段树节点维护一个数组sum[20],分别表示选1-20个数的积的和,
为了方便,令sum[x]=1,手(看)玩小的(题解)后得到合并式
rt.sum[i]=∑j=0ils.sum[j]∗rs.sum[i−j]
r
t
.
s
u
m
[
i
]
=
∑
j
=
0
i
l
s
.
s
u
m
[
j
]
∗
r
s
.
s
u
m
[
i
−
j
]
大概就是卷积……
虽然已经确定了标记下放的顺序,但还需要想想怎么下放……
对x节点的区间取反,直接把x节点的所有编号为奇数的sum取反,偶数sum不变,因为偶数里的全是偶数项,负号抵消……
对x节点的区间加,设有三个数
(a,b,c),(a+v)∗(b+v)∗(c+v)=abc+v(ab+ac+bc)+v2(a+b+c)+v3
(
a
,
b
,
c
)
,
(
a
+
v
)
∗
(
b
+
v
)
∗
(
c
+
v
)
=
a
b
c
+
v
(
a
b
+
a
c
+
b
c
)
+
v
2
(
a
+
b
+
c
)
+
v
3
扩展后得到 sum[i]=∑j=1i(sum[i−j]∗Cjlen−i+j∗xj) s u m [ i ] = ∑ j = 1 i ( s u m [ i − j ] ∗ C l e n − i + j j ∗ x j )
然后就可做了……………………
时间复杂度 O(c2nlogn) O ( c 2 n l o g n )
我在预处理组合数的时候没有输入n……因为这个de了三天bug……
我的收获:丧病的推式子……线段树维护奇 ♂ ♂ <script type="math/tex" id="MathJax-Element-65">♂</script>怪的东西
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define P 19940417
#define M 50005
#define ll long long
#define ls x<<1
#define rs x<<1|1
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
#define root 1,n,1
int n,m,a[M];
int len[M<<2];
ll add[M<<2],c[M][21];
bool rev[M<<2];
struct tree{ll p[21];}s[M<<2];
inline void A(ll &x,ll y){x+=y;if(x>=P) x-=P;}
tree operator +(tree a,tree b){
tree c;c.p[0]=1;
for(int i=1;i<=20;i++){
c.p[i]=0;
for(int j=0;j<=i;j++)
A(c.p[i],a.p[j]*b.p[i-j]%P);
}
return c;
}
void ins(int x,int v){
A(add[x],v);
for(int i=20;i>=1;i--){
ll y=v;
for(int j=1;j<=i;j++,y=y*v%P)
A(s[x].p[i],y*s[x].p[i-j]%P*c[len[x]-i+j][j]%P);
}
}
void turn(int x){
rev[x]^=1;if(add[x]) add[x]=P-add[x];
for(int i=1;i<=20;i+=2) if(s[x].p[i]) s[x].p[i]=P-s[x].p[i];
}
void pushdown(int x){
if(rev[x]) turn(ls),turn(rs),rev[x]=0;
if(add[x]) ins(ls,add[x]),ins(rs,add[x]),add[x]=0;
}
void build(int l,int r,int x)
{
len[x]=r-l+1,s[x].p[0]=1;
if (l==r){s[x].p[1]=a[l]%P;return ;}
int m=(l+r)>>1;
build(lson),build(rson);
s[x]=s[ls]+s[rs];
}
void rever(int L,int R,int l,int r,int x)
{
if(L<=l&&r<=R){turn(x);return ;}
pushdown(x);
int m=(l+r)>>1;
if(L<=m) rever(L,R,lson);
if(R>m) rever(L,R,rson);
s[x]=s[ls]+s[rs];
}
void updata(int L,int R,int v,int l,int r,int x)
{
if(L<=l&&r<=R){ins(x,v);return ;}
pushdown(x);
int m=(l+r)>>1;
if(L<=m) updata(L,R,v,lson);
if(R>m) updata(L,R,v,rson);
s[x]=s[ls]+s[rs];
}
tree query(int L,int R,int z,int l,int r,int x)
{
if(L<=l&&r<=R) return s[x];
pushdown(x);
int m=(l+r)>>1;
if(L<=m&&R>m) return query(L,R,z,lson)+query(L,R,z,rson);
if(L<=m) return query(L,R,z,lson);
if(R>m) return query(L,R,z,rson);
}
void prec()
{
for(int i=0;i<=n;i++){
c[i][0]=1;
for(int j=1;j<=i&&j<=20;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%P;
}
}
void work()
{
char opt[3];int x,y,z;
while(m--){
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='I') scanf("%d",&z),z=(z+P)%P,updata(x,y,z,root);
else if(opt[0]=='R') rever(x,y,root);
else scanf("%d",&z),printf("%lld\n",query(x,y,z,root).p[z]);
}
}
void init()
{
cin>>n>>m;
prec();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(root);
}
int main()
{
init();
work();
return 0;
}