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] ...
随机推荐
- jQuery each用法及each解析json
$(function(){ $("button").click( function(){ var a1=""; var a2=""; var ...
- 与你相遇好幸运,async解决循环回调问题
由于使用的sailsjs框架,用的是sailsjs自身带的ORm(就是waterline),ORM的默认数据库的返回值在回调里面. > arg是一个数组 count用来计数用 tmpArr临时存 ...
- java.lang.UnsupportedClassVersionError: org/xwiki/xxx : Unsupported major.minor version 51.0
此类问题主要是因为Unsupported major.minor version 51.0. 原因是JDK版本不一致导致的问题.在web应用中碰到此问题. 应用中规定使用JDK7.0,本地JDK为6. ...
- C# RFID windows 服务 串口方式
话说RFID以前很火所以整理一下一年前自己处理的RFID程序,放源码. 一开始觉得他是个很神奇的东西. 包含串口通讯和网络通讯. 由于网络通讯设备太贵,所以国内的设备基本上都是在外置一个比较便宜的模块 ...
- 使用android ProgressBar和Toast生成一个界面
首先我需要这样一个界面 这个界面是在使用AudioManager.adjustStreamVolume(int streamType, int direction, int flags)显示出来的,记 ...
- python logging模块 basicConfig配置文件
logging.basicConfig(level=log_level, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s ...
- 【maven】 pom.xml详解
pom.xml详解 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...
- 关于c中 int, float, double转换中存在的精度损失问题
先看一段代码实验: #include<limits> #include<iostream> using namespace std; int main() { unsigned ...
- nodejs随记01
EventEmitter var stream = require('stream'); var Readable = stream.Readable; //写入类(http-req就是),初始化时会 ...
- no-jquery 04 Events
Events Sending Native (DOM) Events anchorElement.click(); Sending Custom Events var event = document ...