2962: 序列操作

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 678  Solved: 246
[Submit][Status][Discuss]

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的值。

Input

  第一行两个数n,q表示序列长度和操作个数。
  第二行n个非负整数,表示序列。
  接下来q行每行输入一个操作I a b c或者 R a b或者Q a b c意义如题目描述。

Output

  对于每个询问,输出选出c个数相乘的所有方案的和mod19940417的值。

Sample Input

5 5
1 2 3 4 5
I 2 3 1
Q 2 4 2
R 1 5
I 1 3 -1
Q 1 5 1

Sample Output

40
19940397
样例说明
  做完第一个操作序列变为1 3 4 4 5。
  第一次询问结果为3*4+3*4+4*4=40。
  做完R操作变成-1 -3 -4 -4 -5。
  做完I操作变为-2 -4 -5 -4 -5。
  第二次询问结果为-2-4-5-4-5=-20。

HINT

  100%的数据n<=50000,q<=50000,初始序列的元素的绝对值<=109,I a b c中保证[a,b]是一个合法区间,|c|<=109,R a b保证[a,b]是个合法的区间。Q a b c中保证[a,b]是个合法的区间1<=c<=min(b-a+1,20)。

Source

中国国家队清华集训 2012-2013 第三天

Solution

线段树维护区间卷积

我们每个区间维护sum[1~20]分别表示选1~20个数的积的和

然后问题在于合并以及修改

合并非常简单$rt.sum[i]=\sum_{j=1}^{i}ls.sum[j]*rs.sum[i-j]$ (手写小的就可以得到)

至于区间取反,直接对区间的所有奇数$sum$取反,偶数$sum$不变。 因为 偶数里的全是偶数项,负号会抵消

区间修改,问题是下放标记时,我们发现假设我们有三个数a,b,c;我们修改时同时+x,那么他们的变化就是

$(a+x)*(b+x)*(c+x)=abc+x(ab+ac+bc)+x^{2}(a+b+c)+x^{3}$这样我们发现,拓展到之后可以得到$sum[i]=\sum_{j=0}^{i}sum[i-j]*C_{sz-j}^{i}*x^{i-j}$

然后我们就可以利用线段树维护了,特别地$sum[0]=1$,中间过程会爆int;

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 80010
#define P 19940417
int N,Q,C[MAXN][];
namespace SegmentTree
{
struct SumNode{int sum[];};
struct SegmentTreeNode{int l,r,size,tag; SumNode p; bool rev;}tree[MAXN<<];
#define ls now<<1
#define rs now<<1|1
inline void Add(int &x,int y) {x+=y; while (x>=P) x-=P; while (x<) x+=P;}
inline SumNode Merge(SegmentTreeNode x,SegmentTreeNode y)
{
SumNode re; re.sum[]=;
for (int i=; i<=; i++)
{
re.sum[i]=(x.p.sum[i]+y.p.sum[i])%P;
for (int j=; j<=i-; j++)
Add(re.sum[i],(LL)x.p.sum[j]*y.p.sum[i-j]%P);
}
return re;
}
inline void Update(int now) {tree[now].p=Merge(tree[ls],tree[rs]);}
inline void rever(int now)
{
tree[now].rev^=;
if (tree[now].tag) tree[now].tag=(P-tree[now].tag%P)%P;
for (int i=; i<=; i++) if ((i&) && tree[now].p.sum[i]) tree[now].p.sum[i]=(P-tree[now].p.sum[i])%P;
}
inline void change(int now,int D)
{
Add(tree[now].tag,D);
for (int t=D,i=; i; i--,t=D)
{
for (int j=i-; j; j--,t=(LL)t*D%P)
Add(tree[now].p.sum[i],(LL)t*tree[now].p.sum[j]%P*C[tree[now].size-j][i-j]%P);
Add(tree[now].p.sum[i],(LL)t*C[tree[now].size][i]%P);
}
}
inline void PushDown(int now)
{
if (tree[now].rev) {rever(ls); rever(rs); tree[now].rev=;}
if (tree[now].tag) {change(ls,tree[now].tag); change(rs,tree[now].tag); tree[now].tag=;}
}
inline void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r; tree[now].size=r-l+;
tree[now].p.sum[]=; tree[now].tag=; tree[now].rev=;
if (l==r) {tree[now].p.sum[]=(read()+P)%P; return;}
int mid=(l+r)>>;
BuildTree(ls,l,mid); BuildTree(rs,mid+,r);
Update(now);
}
inline void Reverse(int now,int L,int R)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) {rever(now); return;}
PushDown(now);
int mid=(l+r)>>;
if (L<=mid) Reverse(ls,L,R);
if (R>mid) Reverse(rs,L,R);
Update(now);
}
inline void Change(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) {change(now,D); return;}
PushDown(now);
int mid=(l+r)>>;
if (L<=mid) Change(ls,L,R,D);
if (R>mid) Change(rs,L,R,D);
Update(now);
}
inline SegmentTreeNode Query(int now,int L,int R,int D)
{
int l=tree[now].l,r=tree[now].r;
if (L==l && R==r) return tree[now];
PushDown(now);
int mid=(l+r)>>; SegmentTreeNode re;
if (R<=mid) return Query(ls,L,R,D);
else if (L>mid) return Query(rs,L,R,D);
else return re.p=Merge(Query(ls,L,mid,D),Query(rs,mid+,R,D)),re;
}
}
void GetC()
{
C[][]=;
for (int i=; i<=N; i++)
{
C[i][]=;
for (int j=; j<=min(i,); j++) C[i][j]=(C[i-][j]+C[i-][j-])%P;
}
}
using namespace SegmentTree;
int main()
{
// freopen("sequence.in","r",stdin);
// freopen("sequence.out","w",stdout);
N=read(),Q=read();
GetC();
SegmentTree::BuildTree(,,N);
// for (int i=1; i<=N; i++) printf("%I64d ",Query(1,1,N,i).p.sum[i]); puts("");
// puts("============================================");
while (Q--)
{
char opt[]; scanf("%s",opt); int x,y,z;
switch (opt[])
{
case 'I' : x=read(),y=read(),z=(read()+P)%P; SegmentTree::Change(,x,y,z); break;
case 'Q' : x=read(),y=read(),z=read(); printf("%d\n",SegmentTree::Query(,x,y,z).p.sum[z]); break;
case 'R' : x=read(),y=read(); SegmentTree::Reverse(,x,y); break;
}
// puts("============================================");
// for (int i=1; i<=N; i++) printf("%d\n",Query(1,1,N,i).p.sum[i]); puts("");
// printf("%d %d %d\n",x,y,z);
// puts("============================================");
}
return ;
}

%来%去太鬼畜了

数组少打一个0,BZOJ楞是WA,就是不报RE,小数据妥妥拍不到,纸张

差点搞得自己以后再也不能叫char哥....

【BZOJ-2962】序列操作 线段树 + 区间卷积的更多相关文章

  1. bzoj 2962 序列操作——线段树(卷积?)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 如果 _,_,_,…… 变成了 (_+k),(_+k),(_+k),…… ,计算就是在 ...

  2. bzoj 2962 序列操作 —— 线段树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2962 维护 sum[i] 表示选 i 个的乘积和,合并两个子树就枚举两边选多少,乘起来即可: ...

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

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

  4. [bzoj]2962序列操作

    [bzoj]2962序列操作 标签: 线段树 题目链接 题意 给你一串序列,要你维护三个操作: 1.区间加法 2.区间取相反数 3.区间内任意选k个数相乘的积 题解 第三个操作看起来一脸懵逼啊. 其实 ...

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

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

  6. Bzoj 1798: [Ahoi2009]Seq 维护序列seq(线段树区间操作)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小可 ...

  7. hdu4521-小明系列问题——小明序列(线段树区间求最值)

    题意:求最长上升序列的长度(LIS),但是要求相邻的两个数距离至少为d,数据范围较大,普通dp肯定TLE.线段树搞之就可以了,或者优化后的nlogn的dp. 代码为  线段树解法. #include ...

  8. bzoj 2962 序列操作

    2962: 序列操作 Time Limit: 50 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 有一个长度为n的序列, ...

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

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

随机推荐

  1. C语言:将结构体存放到文件中

    #include <stdio.h> #include <stdlib.h> #define MAXTLEN 70 #define MAXALEN 70 #define MAX ...

  2. delphi附带通用控件安装方法:

    附带通用控件安装方法:----------基本安装1.对于单个控件,Componet-->install component..-->PAS或DCU文件-->install;2.对于 ...

  3. git 解决fatal: Not a git repository

    我用git add file添加文件时出现这样错误: fatal: Not a git repository (or any of the parent directories): .git 提示说没 ...

  4. noip2008 双栈排序

    题目描述 Description \(Tom\)最近在研究一个有趣的排序问题.如图所示,通过\(2\)个栈\(S_1\)和\(S_2\),\(Tom\)希望借助以下\(4\)种操作实现将输入序列升序排 ...

  5. 上传Text文档并转换为PDF(解决乱码)

    前些日子,Insus.NET有分享一篇<上传Text文档并转换为PDF>http://www.cnblogs.com/insus/p/4313092.html 它是按最简单与默认方式来处理 ...

  6. (转)c# 解析JSON的几种办法

    来自:http://blog.csdn.net/gaofang2009/article/details/6073029 欲成为海洋大师,必知晓海中每一滴水的真名. 刚开始只是想找一个转换JSON数组的 ...

  7. Gruntjs: grunt-usemin使用心得

    grunt-usemin: Replaces references to non-optimized scripts or stylesheets into a set of HTML files u ...

  8. spring 3.2.x + struts2 + mybatis 3.x + logback 整合配置

    与前面的一篇mybatis 3.2.7 与 spring mvc 3.x.logback整合 相比,只是web层的MVC前端框架,从spring mvc转换成struts 2.x系列,变化并不大 一. ...

  9. scrapy 保存到 sqlite3

    scrapy 爬取到结果后,将结果保存到 sqlite3,有两种方式 item Pipeline Feed Exporter 方式一 使用 item Pipeline 有三个步骤 文件 pipelin ...

  10. 实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...