zoukankan      html  css  js  c++  java
  • bzoj 2962: 序列操作

    Description

      有一个长度为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的值。

    Solution

    注意到 (c) 比较小,可以直接维护一个 (O(20^2))(DP)
    即设 (f[i]) 表示选了 (i) 个数相乘的方案
    用线段树维护
    合并的话就是 (f[o][i]=sum_{j=0}^{i} f[ls][j]*f[rs][i-j])

    考虑修改
    加上 (x),其实就是把所有的 (a*b*c) 变成 ((a+x)*(b+x)*(c+x))
    用展开就是:
    (a*b*c+(ab+bc+ac)*x+(a+b+c)*x^2+x^3)
    那么 (f[i]) 修改之后的值就是
    (f[i]=sum_{j=1}^{i}f[j]*C_{len-j}^{i-j}*x^{i-j})
    (len) 是区间长度,因为这个多项式是有 (len) 项的,所以要乘以组合数

    对于变成相反数的操作,要注意:
    不仅维护的值要变,标记也要取反

    #include <bits/stdc++.h>
    #define ls (o<<1)
    #define rs (o<<1|1)
    using namespace std;
    const int N=50010,mod=19940417;
    inline int gi(){
    	register int str=0;register char ch=getchar();bool fg=0;
    	while(ch>'9' || ch<'0'){if(ch=='-')fg=1;ch=getchar();}
    	while(ch>='0' && ch<='9')str=(str<<3)+(str<<1)+ch-48,ch=getchar();
    	return fg?-str:str;
    }
    int n,Q,c[N][25],f[25],la[N*4];bool rev[N*4];
    struct data{int b[25];data(){memset(b,0,sizeof(b));b[0]=1;}}tr[N*4];
    inline void priwork(){
    	for(int i=0;i<=n;i++){
    		c[i][0]=1;
    		for(int j=min(20,i);j>=1;j--)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    	}
    }
    inline data merge(data x,data y){
    	data r;
    	for(int i=1;i<=20;i++)
    		for(int j=0;j<=i;j++)
    			r.b[i]=(r.b[i]+1ll*x.b[j]*y.b[i-j])%mod;
    	return r;
    }
    inline void build(int l,int r,int o){
    	if(l==r){tr[o].b[1]=gi()%mod;return ;}
    	int mid=(l+r)>>1;
    	build(l,mid,ls);build(mid+1,r,rs);
    	tr[o]=merge(tr[ls],tr[rs]);
    }
    inline void Rec1(int o,int t,int l,int r){
    	la[o]=(la[o]+t)%mod;
    	for(int len=r-l+1,i=min(len,20);i>=1;i--){
    		f[i]=0;
    		for(int j=i,tp=1;j>=0;j--,tp=1ll*tp*t%mod)
    			f[i]=(f[i]+1ll*tr[o].b[j]*c[len-j][i-j]%mod*tp)%mod;
    	}
    	for(int i=min(r-l+1,20);i>=1;i--)tr[o].b[i]=f[i];
    }
    inline void Rec2(int o){
    	rev[o]^=1;la[o]=(mod-la[o])%mod;
    	for(int i=1;i<=20;i+=2)tr[o].b[i]=(mod-tr[o].b[i])%mod;
    }
    inline void pushdown(int o,int l,int r){
    	if(rev[o])Rec2(ls),Rec2(rs),rev[o]=0;
    	if(la[o]){
    		int mid=(l+r)>>1;
    		Rec1(ls,la[o],l,mid),Rec1(rs,la[o],mid+1,r),la[o]=0;
    	}
    }
    inline void add(int l,int r,int o,int sa,int se,int t){
    	if(sa<=l && r<=se){Rec1(o,t,l,r);return ;}
    	pushdown(o,l,r);
    	int mid=(l+r)>>1;
    	if(se<=mid)add(l,mid,ls,sa,se,t);
    	else if(sa>mid)add(mid+1,r,rs,sa,se,t);
    	else add(l,mid,ls,sa,mid,t),add(mid+1,r,rs,mid+1,se,t);
    	tr[o]=merge(tr[ls],tr[rs]);
    }
    inline void Modify(int l,int r,int o,int sa,int se){
    	if(sa<=l && r<=se){Rec2(o);return ;}
    	pushdown(o,l,r);
    	int mid=(l+r)>>1;
    	if(se<=mid)Modify(l,mid,ls,sa,se);
    	else if(sa>mid)Modify(mid+1,r,rs,sa,se);
    	else Modify(l,mid,ls,sa,mid),Modify(mid+1,r,rs,mid+1,se);
    	tr[o]=merge(tr[ls],tr[rs]);
    }
    inline data qry(int l,int r,int o,int sa,int se){
    	if(sa<=l && r<=se)return tr[o];
    	pushdown(o,l,r);
    	int mid=(l+r)>>1;data ret;
    	if(se<=mid)ret=qry(l,mid,ls,sa,se);
    	else if(sa>mid)ret=qry(mid+1,r,rs,sa,se);
    	else ret=merge(qry(l,mid,ls,sa,mid),qry(mid+1,r,rs,mid+1,se));
    	tr[o]=merge(tr[ls],tr[rs]);
    	return ret;
    }
    int main()
    {
    	freopen("pp.in","r",stdin);
    	freopen("pp.out","w",stdout);
    	cin>>n>>Q;priwork();
    	build(1,n,1);
    	char s[2];int l,r;
    	while(Q--){
    		scanf("%s%d%d",s,&l,&r);
    		if(s[0]=='I')add(1,n,1,l,r,gi()%mod);
    		else if(s[0]=='R')Modify(1,n,1,l,r);
    		else printf("%d
    ",(qry(1,n,1,l,r).b[gi()]+mod)%mod);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    基于Adaboost的人脸检测算法
    操作系统笔试题及答案
    eclipse Maven plugin 配置
    网站服务管理系统系列教程之五
    2017第4周日
    2017春节~人生智慧箴言
    2017年初夕
    2017农历二十九
    王国维收藏真伪
    2017第3周二假期里该做的事
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8634001.html
Copyright © 2011-2022 走看看