bzoj2962 序列操作 线段树

来源:互联网 发布:筑业标书制作软件 编辑:程序博客网 时间:2024/06/09 14:26

题意:一段序列,三种操作:
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[ij];(j<i)
取负也很简单,只有奇数的时候才会有影响。
问题就是区间加有些难以处理。
假设加上x,区间长度为len,那么就是类似于(.....+x)(.....+x)(......+x)这样的一个东西。
那么我们枚举x有j个,答案就是j=0ixjf[ij]Cjleni+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[N];int c[N][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;}