bzoj2962 序列操作 题解
题目大意:
有一个长度为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的值。
思路:
显然需要用线段树维护一个数组sum[c]表示选c个数相乘的方案总和。合并的时候只要枚举c,然后枚举左边选几个数然后和右边的乘起来累加进去就好了。取反实际上就是把所有c为奇数的取反,关键是区间加。对于[l,r],区间+x,那么枚举c。注意到形式是这样的: newsum[c]=Σ(a1+x)(a2+x)...(ac+x),然后按照x的次数合并同类项,可以发现这个东西可以通过x^k,组合数C(r-l+1,k)和oldsum[c-k]得到答案。k为x的次数。其余就是普通的线段树了。注意:推标记时要注意顺序。
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 150000
#define mod 19940417
#define ll long long
using namespace std; int lazy[N],zhs[N][],size[N];
struct node{int sum[];}ans[N];
bool rev[N]; int read()
{
int x=,y=;
char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') y=-;ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-;ch=getchar();}
return x*y;
} void add(int &x,int y)
{
x+=y;
if (x>=mod) x-=mod;
} void up_date(int k)
{
for (int i=;i<=;i++)
{
ans[k].sum[i]=;
for (int j=;j<i;j++) add(ans[k].sum[i],(ll)ans[k<<].sum[j]*ans[k<<|].sum[i-j]%mod);
add(ans[k].sum[i],ans[k<<].sum[i]);add(ans[k].sum[i],ans[k<<|].sum[i]);
}
} void ins(int k,int val)
{
add(lazy[k],val);
for (int i=;i;i--)
{
int x=val,j;
for (j=i-;j;j--,x=(ll)x*val%mod)
add(ans[k].sum[i],(ll)x*ans[k].sum[j]%mod*zhs[size[k]-j][i-j]%mod);
add(ans[k].sum[i],(ll)x*zhs[size[k]][i]%mod);
}
} void turn(int k)
{
int i; rev[k]^=;
if (lazy[k]) lazy[k]=mod-lazy[k];
for (i=;i>;i-=) if (ans[k].sum[i]) ans[k].sum[i]=mod-ans[k].sum[i];
} void build(int l,int r,int cur)
{
size[cur]=r-l+;
if (l==r) {ans[cur].sum[]=read()%mod;return;}
int mid=(l+r)>>;
build(l,mid,cur<<),build(mid+,r,cur<<|),up_date(cur);
} void push_down(int k)
{
if (rev[k]) turn(k<<),turn(k<<|),rev[k]=;
if (lazy[k])ins(k<<,lazy[k]),ins(k<<|,lazy[k]),lazy[k]=;
} void fan(int l,int r,int k,int x,int y)
{
if (l==x && r==y){ turn(k); return; }
int mid=l+r>>; push_down(k);
if (y<=mid) fan(l,mid,k<<,x,y);
else if (x>mid) fan(mid+,r,k<<|,x,y);
else fan(l,mid,k<<,x,mid),fan(mid+,r,k<<|,mid+,y);
up_date(k);
} void jia(int L,int R,int cur,int l,int r,int val)
{
if (l==L && r==R) {ins(cur,val);return;}
int mid=(L+R)>>; push_down(cur);
if (r<=mid) jia(L,mid,cur<<,l,r,val);
else if (l>mid) jia(mid+,R,cur<<|,l,r,val);
else jia(L,mid,cur<<,l,mid,val),jia(mid+,R,cur<<|,mid+,r,val);
up_date(cur);
} node ask(int L,int R,int cur,int l,int r,int val)
{
if (l==L && r==R) return ans[cur];
int mid=(L+R)>>; push_down(cur);
if (l>mid) return ask(mid+,R,cur<<|,l,r,val);
else if (r<=mid) return ask(L,mid,cur<<,l,r,val);
else
{
node x=ask(L,mid,cur<<,l,mid,val),y=ask(mid+,R,cur<<|,mid+,r,val),t;
for (int i=;i<=val;i++)
{
t.sum[i]=(x.sum[i]+y.sum[i])%mod;
for (int j=;j<i;j++) add(t.sum[i],(ll)x.sum[j]*y.sum[i-j]%mod);
}
return t;
}
} int main()
{
int n=read(),m=read(),i,j;
zhs[][]=;
for (i=;i<=n;i++)
{
zhs[i][]=;
for (j=;j<=i && j<=;j++) zhs[i][j]=(zhs[i-][j-]+zhs[i-][j])%mod;
}
build(,n,);
while (m--)
{
char ch=getchar();
while (ch<'A' || ch>'Z') ch=getchar();
if (ch=='I')
{
int x=read(),y=read(),z=read()%mod;
if (z<) z+=mod; jia(,n,,x,y,z);
}
if (ch=='R')
{
int x=read(),y=read();
fan(,n,,x,y);
}
if (ch=='Q')
{
int x=read(),y=read(),z=read();
printf("%d\n",ask(,n,,x,y,z).sum[z]);
}
}
return ;
}
bzoj2962 序列操作 题解的更多相关文章
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
- bzoj2962 序列操作
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 1145 Solved: 378[Submit][Status][Discuss ...
- BZOJ1858[Scoi2010]序列操作 题解
题目大意: 有一个01序列,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0:1 a b 把[a, b]区间内的所有数全变成1:2 a b 把[a,b]区间 ...
- BZOJ1858:[SCOI2010]序列操作——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=1858 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于 ...
- 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)
传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...
- 【BZOJ2962】序列操作(线段树)
[BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...
- 【BZOJ2962】序列操作 线段树
[BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
随机推荐
- 虚拟机Class文件结构笔记
>>Java语言的平台无关性 Java是与平台无关的语言,“一次编写,到处运行”,这一方面依赖于Java源代码编译后生成的存储字节码的文件,即Class文件是语言和平台无关的: 另一方面依 ...
- Delphi的枚举类型
参考:http://blog.csdn.net/kissdeath/article/details/2060573 Delphi程序不仅可以用于数值处理,还更广泛的用于处理非数值的数据.例如:性别.月 ...
- Pyqt 以OOP方式动画的效果改变自身窗体大小
代码: # -*- coding:utf8 -*- from PyQt4.QtGui import * from PyQt4.QtCore import * import sys class ani( ...
- 最终排名 sdut 2446
最终排名 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 题目链接:http://acm.sdut.edu.cn/sdutoj/p ...
- 图结构练习——最短路径(floyd算法(弗洛伊德))
图结构练习——最短路径 Time Limit: 1000ms Memory limit: 65536K 有疑问?点这里^_^ 题目描述 给定一个带权无向图,求节点1到节点n的最短路径. 输 ...
- hdu 4049 2011北京赛区网络赛J 状压dp ***
cl少用在for循环里 #include<cstdio> #include<iostream> #include<algorithm> #include<cs ...
- WebRTC之带宽控制部分学习(1) ------基本demo的介绍
转自:http://blog.csdn.net/u013160228/article/details/46392037 WebRTC的代码真是非常之大啊,下载以及编译了我好几天才搞完..... 可以看 ...
- mysql的启动
1.直接用mysqld手工启动 [root@ora11g bin]# ./mysqld --defaults-file=../my.cnf :: [ERROR] Fatal error: Please ...
- 第十一篇:SOUI系统资源管理
SOUI资源管理模块 从前篇已经讲到在SOUI中所有资源文件通过一个uires.idx文件进行索引. 这里将介绍在程序中如何引用这些资源文件. 在SOUI系统中,资源文件通过一个统一的接口对象读取: ...
- python学习-爬虫
转载自 静觅的博客 最普通下载网页 import urrlib2 response = urllib2.urlopen("http://www.baidu.com") print ...