bzoj2962 序列操作 线段树
2017-09-16 08:40
411 查看
题意:一段序列,三种操作:
1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。
一开始没看到k<=20,觉得不可做,后来一看,哦这不就水了很多了。。
操作3的话维护f[i]表示当前区间选择i个的答案,那么n^2更新,明显有:
f[i]=f[j]∗f[i−j];(j<i)
取负也很简单,只有奇数的时候才会有影响。
问题就是区间加有些难以处理。
假设加上x,区间长度为len,那么就是类似于(.....+x)(.....+x)(......+x)这样的一个东西。
那么我们枚举x有j个,答案就是∑j=0ixj∗f[i−j]∗Cjlen−i+j
后面那个组合数应该挺好理解,i-j个数字被确定,剩下的len-i+j个中选出j个x。
3000多B让我有点爽。。
1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这一段区间中选择c个数相乘的所有方案的和mod 19940417的值。
一开始没看到k<=20,觉得不可做,后来一看,哦这不就水了很多了。。
操作3的话维护f[i]表示当前区间选择i个的答案,那么n^2更新,明显有:
f[i]=f[j]∗f[i−j];(j<i)
取负也很简单,只有奇数的时候才会有影响。
问题就是区间加有些难以处理。
假设加上x,区间长度为len,那么就是类似于(.....+x)(.....+x)(......+x)这样的一个东西。
那么我们枚举x有j个,答案就是∑j=0ixj∗f[i−j]∗Cjlen−i+j
后面那个组合数应该挺好理解,i-j个数字被确定,剩下的len-i+j个中选出j个x。
3000多B让我有点爽。。
#include<cstdio> #include<algorithm> #include<cstring> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int N=50005; const int mo=19940417; typedef long long ll; int n,m; struct node { int l,r,lazy1,lazy2; ll f[21];; }t[N*5]; int a ; int c [30]; inline void update(int x) { fo(i,0,20) { t[x].f[i]=0; fo(j,0,i)t[x].f[i]=(t[x].f[i]+t[x<<1].f[j]*t[x<<1|1].f[i-j])%mo; } } inline void push1(int x) { for(int i=1;i<=20;i+=2)t[x].f[i]*=-1; } inline void push2(int x,int l,int r,int v) { int len=r-l+1; fd(i,min(len,20),1) { ll tmp=0;int mi=1; fo(j,0,i)tmp=(tmp+1ll*mi*t[x].f[i-j]%mo*c[len-i+j][j])%mo,mi=1ll*mi*v%mo; t[x].f[i]=tmp; } } inline void build(int x,int l,int r) { t[x].l=l,t[x].r=r;t[x].lazy1=1; if (l==r) { t[x].f[1]=a[l]; t[x].f[0]=1; return; } int mid=(l+r)>>1; build(x<<1,l,mid); build(x<<1|1,mid+1,r); update(x); } inline void pushdown(int x,int l,int r) { if (l==r)return; int mid=(l+r)>>1,w=t[x].lazy2; if (t[x].lazy1==-1) { push1(x<<1),push1(x<<1|1); t[x<<1].lazy1*=-1,t[x<<1|1].lazy1*=-1; t[x<<1].lazy2*=-1,t[x<<1|1].lazy2*=-1; t[x].lazy1=1; } if (w) { push2(x<<1,l,mid,w),push2(x<<1|1,mid+1,r,w); t[x<<1].lazy2=(t[x<<1].lazy2+w)%mo; t[x<<1|1].lazy2=(t[x<<1|1].lazy2+w)%mo; t[x].lazy2=0; } } inline void add(int x,int l,int r,int v) { if (l>r)return; pushdown(x,t[x].l,t[x].r); if (t[x].l==l&&t[x].r==r) { push2(x,t[x].l,t[x].r,v); t[x].lazy2=(t[x].lazy2+v)%mo; return; } int mid=(t[x].l+t[x].r)>>1; add(x<<1,l,min(r,mid),v); add(x<<1|1,max(l,mid+1),r,v); update(x); } inline void oppo(int x,int l,int r) { if (l>r)return; pushdown(x,t[x].l,t[x].r); if (t[x].l==l&&t[x].r==r) { push1(x); t[x].lazy1*=-1; return; } int mid=(t[x].l+t[x].r)>>1; oppo(x<<1,l,min(r,mid)); oppo(x<<1|1,max(l,mid+1),r); update(x); } inline node query(int x,int l,int r,int v) { pushdown(x,t[x].l,t[x].r); if (t[x].l==l&&t[x].r==r)return t[x]; int mid=(t[x].l+t[x].r)>>1; if (r<=mid)return query(x<<1,l,r,v); else if (l>mid)return query(x<<1|1,l,r,v); else { node a=query(x<<1,l,mid,v), b=query(x<<1|1,mid+1,r,v),ans; fo(i,0,v) { ans.f[i]=0; fo(j,0,i) ans.f[i]=(ans.f[i]+a.f[j]*b.f[i-j]%mo)%mo; } return ans; } } int main() { scanf("%d%d",&n,&m); fo(i,1,n)scanf("%d",&a[i]); build(1,1,n); c[0][0]=1; fo(i,1,n) { c[i][0]=1; fo(j,1,20) c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo; } fo(i,1,m) { char ch[2]; int l,r,v; scanf("%s",ch); if (ch[0]=='I')scanf("%d%d%d",&l,&r,&v),add(1,l,r,v%mo); else if (ch[0]=='R')scanf("%d%d",&l,&r),oppo(1,l,r); else { scanf("%d%d%d",&l,&r,&v); node x=query(1,l,r,v); printf("%lld\n",(x.f[v]+mo)%mo); } } return 0; }
相关文章推荐
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
- [BZOJ2962]序列操作(线段树)
- bzoj 2962 序列操作(线段树)
- 序列操作 BZOJ2962 线段树
- bzoj 2962: 序列操作 线段树
- [bzoj2962]序列操作_线段树_区间卷积
- bzoj 2962 序列操作 线段树
- 【bzoj2962】序列操作 线段树
- BZOJ_2962_序列操作_线段树
- BZOJ 2962 序列操作 线段树
- 【BZOJ2962】序列操作(线段树)
- 【BZOJ2962】序列操作(线段树)
- bzoj 2962: 序列操作 线段树
- 【bzoj2962】【序列操作】【线段树】
- 【BZOJ2962】序列操作 线段树
- BZOJ 2962 序列操作 线段树
- bzoj1858:序列操作 (线段树区间信息合并)
- [省选] [线段树] [BZOJ1858] [SCOI2010] 序列操作
- BZOJ 1858 [Scoi2010]序列操作 - 线段树
- BZOJ 1858: [Scoi2010]序列操作 [线段树]