传送门

线段树基础题。

题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负。


由于c≤20c\le20c≤20,因此可以对于每个线段树节点可以暴力维护212121个sumsumsum值,合并也很简单,是一个卷积的形式sumi=∑j=0isumjsumi−jsum_i=\sum_{j=0}^isum_jsum_{i-j}sumi​=∑j=0i​sumj​sumi−j​可以用FFT优化一波(滑稽。

区间取负并没有什么难度,对于sumisum_isumi​来说,如果iii是偶数就并没有什么影响,如果iii是奇数把sumisum_isumi​变成−sumi-sum_i−sumi​即可。

关键在于区间加。

考虑到区间加对每个sumsumsum的影响,我们把a1a2...ana_1a_2...a_na1​a2​...an​变成了(a1+x)(a2+x)...(an+x)(a_1+x)(a_2+x)...(a_n+x)(a1​+x)(a2​+x)...(an​+x),我们设这个区间长度为lenlenlen,那么有组合数学的方法可以将这个式子展开:newsumi=∑j=0iClen−ji−jxjoldsumjnewsum_{i}=\sum_{j=0}^iC_{len-j}^{i-j}x^joldsum_jnewsumi​=∑j=0i​Clen−ji−j​xjoldsumj​ 相当于是枚举每个括号里面xxx的个数来更新答案

然后就没啥了~~注意细节~~

代码:

#include<bits/stdc++.h>
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define add(a,b) ((a)+(b)>=mod?(a)+(b)-mod:(a)+(b))
#define mul(a,b) ((ll)(a)*(b)%mod)
#define dec(a,b) ((a)>=(b)?(a)-(b):(a)-(b)+mod)
#define ri register int
using namespace std;
typedef long long ll;
const int mod=19940417,N=5e5+5;
int n,m,a[N],C[N][21];
inline int read(){
	int ans=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans*w;
}
struct Node{int l,r,sum[21],add;bool rev;Node(){l=r=add=rev=0;for(ri i=0;i<=20;++i)sum[i]=0;}}T[N<<2];
inline Node operator+(const Node&a,const Node&b){
	Node ret;
	ret.l=a.l,ret.r=b.r;
	for(ri i=0;i<=20;++i)for(ri j=0;j<=i;++j)ret.sum[i]=add(ret.sum[i],mul(a.sum[j],b.sum[i-j]));
	return ret;
}
inline void pushadd(int p,int v){
	T[p].add=add(T[p].add,v);
	for(ri i=min(T[p].r-T[p].l+1,20),len=T[p].r-T[p].l+1;~i;--i)for(ri j=i-1,mult=v;~j;--j,mult=mul(mult,v))
		T[p].sum[i]=add(T[p].sum[i],mul(C[len-j][i-j],mul(mult,T[p].sum[j])));
}
inline void pushrev(int p){
	T[p].rev^=1,T[p].add=dec(0,T[p].add);
	for(ri i=0;i<=20;++i)if(i&1)T[p].sum[i]=dec(0,T[p].sum[i]);
}
inline void pushdown(int p){
	if(T[p].rev)pushrev(lc),pushrev(rc),T[p].rev^=1;
	if(T[p].add)pushadd(lc,T[p].add),pushadd(rc,T[p].add),T[p].add=0;
}
inline void build(int p,int l,int r){
	T[p].l=l,T[p].r=r;
	if(T[p].l==T[p].r){T[p].sum[0]=1,T[p].sum[1]=a[l];return;}
	build(lc,l,mid),build(rc,mid+1,r),T[p]=T[lc]+T[rc];
}
inline void update(int p,int ql,int qr,int v){
	if(ql<=T[p].l&&T[p].r<=qr)return v?pushadd(p,v):pushrev(p);
	pushdown(p);
	if(qr<=mid)update(lc,ql,qr,v);
	else if(ql>mid)update(rc,ql,qr,v);
	else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
	T[p]=T[lc]+T[rc];
}
inline Node query(int p,int ql,int qr){
	if(ql<=T[p].l&&T[p].r<=qr)return T[p];
	pushdown(p);
	if(qr<=mid)return query(lc,ql,qr);
	if(ql>mid)return query(rc,ql,qr);
	return query(lc,ql,mid)+query(rc,mid+1,qr);
}
inline void init(){
	for(ri i=0;i<=n;++i)C[i][0]=1;
	for(ri i=1;i<=n;++i){
		C[i][1]=i;
		for(ri j=2;j<=min(20,i);++j)C[i][j]=add(C[i-1][j],C[i-1][j-1]);
	}
	build(1,1,n);
}
int main(){
	n=read(),m=read();
	for(ri i=1;i<=n;++i)a[i]=(read()%mod+mod)%mod;
	init();
	while(m--){
		char s[2];
		scanf("%s",s);
		int l=read(),r=read(),v;
		if(s[0]=='I'){
			v=(read()%mod+mod)%mod;
			if(!v)continue;
			update(1,l,r,v);
		}
		else if(s[0]=='R')update(1,l,r,0);
		else cout<<query(1,l,r).sum[read()]<<'\n';
	}
	return 0;
}

2019.01.04 bzoj2962: 序列操作(线段树+组合数学)的更多相关文章

  1. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  2. 【BZOJ2962】序列操作 线段树

    [BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...

  3. 【BZOJ-2962】序列操作 线段树 + 区间卷积

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 678  Solved: 246[Submit][Status][Discuss] ...

  4. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1961  Solved: 991[Submit][Status ...

  5. BZOJ 1858: [Scoi2010]序列操作( 线段树 )

    略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...

  6. 【bzoj1858】[Scoi2010]序列操作 线段树区间合并

    题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...

  7. Luogu P2572 [SCOI2010]序列操作 线段树。。

    咕咕了...于是借鉴了小粉兔的做法ORZ... 其实就是维护最大子段和的线段树,但上面又多了一些操作....QWQ 维护8个信息:1/0的个数(sum),左/右边起1/0的最长长度(ls,rs),整段 ...

  8. 洛谷$P2572\ [SCOI2010]$ 序列操作 线段树/珂朵莉树

    正解:线段树/珂朵莉树 解题报告: 传送门$w$ 本来是想写线段树的,,,然后神仙$tt$跟我港可以用珂朵莉所以决定顺便学下珂朵莉趴$QwQ$ 还是先写线段树做法$QwQ$? 操作一二三四都很$eas ...

  9. bzoj1858[Scoi2010]序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 3079  Solved: 1475[Submit][Statu ...

随机推荐

  1. fullCalendar插件基本使用

    效果图 html代码,需要引入jquery,layui,fullCalendar <!DOCTYPE html> <html lang="en"> < ...

  2. springboot找不到主类

    在学习springboot的时候,前几天写了一个demo,正常运行,一点问题也没有.今天运行不起来了. 报错:找不到主类 解决方案: Project->Clean->选中项目,点击Clea ...

  3. C++求图任意两点间的所有路径

    基于连通图,邻接矩阵实现的图,非递归实现. 算法思想: 设置两个标志位,①该顶点是否入栈,②与该顶点相邻的顶点是否已经访问. A 将始点标志位①置1,将其入栈 B 查看栈顶节点V在图中,有没有可以到达 ...

  4. FortiGate防火墙内存使用率高问题

    1.现象:zabbix监控到防火墙内存使用率频繁超过80%,而FortiGate防火墙内存超过80%将开启自身保护模式而不能新加策略等. 2.分析:这种情况一般是某些进程再释放内存的时候卡住.可以先查 ...

  5. 小服务程序(Java Servlet)

    一般来说,servlet说起来挺高大上的,但是其实实际就是一个能够交互地浏览和修改页面数据,生成一个动态的Web页面. Servlet方法,页面实施请求数据,后台服务器给出响应,将数据返回到页面中去. ...

  6. jQuery与js对象互转

    @参考文章 1 jQuery对象转js 亲测有效 var $v=$("#v"); //jQuery对象 ); //js对象 或 var $v =$("#v") ...

  7. SQL Server 触发器 表的特定字段(一个字段)更新时,触发Update触发器

    CREATE TRIGGER [dbo].[Trg_Update_table1_column1]   on table1  after update  as  if update (column1)  ...

  8. swift - layer - 渐变色 - CAGradientLayer

    1.创建 渐变色 /// 渐变色:默认从上到下 private var gradientLayer: CAGradientLayer = { let g = CAGradientLayer() g.c ...

  9. ABAP空格和零的问题

    空格 concatenate wa_detail-zz_mark1 '' '' '' wa_detail-kdmat1 into wa_detail-zz_mark1 separated by spa ...

  10. 完全卸载jdk

    完全卸载jdk  如(卸载jdk1.7.0_80),  当卸载jdk时出现删除信息不全,导致无法安装,可通过此方法实现完全卸载. 1.打开系统运行输入regedit(注册表)分别查找以下路径  (1) ...