题目大意:

  有一个长度为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 序列操作 题解的更多相关文章

  1. [bzoj2962]序列操作_线段树_区间卷积

    序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...

  2. bzoj2962 序列操作

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

  3. BZOJ1858[Scoi2010]序列操作 题解

    题目大意: 有一个01序列,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0:1 a b 把[a, b]区间内的所有数全变成1:2 a b 把[a,b]区间 ...

  4. BZOJ1858:[SCOI2010]序列操作——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=1858 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于 ...

  5. 2019.01.04 bzoj2962: 序列操作(线段树+组合数学)

    传送门 线段树基础题. 题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c≤20),支持区间加,区间取负. 由于c≤20c\le20c≤20,因此可以对于每个线段树节点可 ...

  6. 【BZOJ2962】序列操作(线段树)

    [BZOJ2962]序列操作(线段树) 题面 BZOJ 题解 设\(s[i]\)表示区间内选择\(i\)个数的乘积的和 考虑如何向上合并? \(s[k]=\sum_{i=0}^klson.s[i]*r ...

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

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

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

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

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

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

随机推荐

  1. 数据结构和算法 – 3.堆栈和队列

    1.栈的实现   后进先出     自己实现栈的代码 using System; using System.Collections.Generic; using System.Linq; using ...

  2. Object.create 函数 (JavaScript)

    创建一个具有指定原型且可选择性地包含指定属性的对象. 语法 Object.create(prototype, descriptors) 参数 prototype 必需.  要用作原型的对象.  可以为 ...

  3. POJ2406 Power Strings(KMP,后缀数组)

    这题可以用后缀数组,KMP方法做 后缀数组做法开始想不出来,看的题解,方法是枚举串长len的约数k,看lcp(suffix(0), suffix(k))的长度是否为n- k ,若为真则len / k即 ...

  4. [译] Extending jQuery Part1 Simple extensions

    本章包含: JQuery 的起源和目标. 你能扩展JQuery 的那些部分. JQuery 扩展的实例. 如今,JQuery 已经是网络上最受欢迎的JavaScript Library. 1.1 jQ ...

  5. [JAVA] IOException: Invalid byte 2 of 2-byte UTF-8 sequence(解决办法)

    日志打印不全,后台只打印出出标题的异常信息: 先前的日志打印信息:log.debug(e.getMessage()); 后面改成了日志打印信息:log.debug(e); log.debug(e.ge ...

  6. myeclipse+tomcat 工程名改名的问题 ——————完美解决方案

    当建好的工程再重命名之后,发布和访问的时候都还是原来的名字,这个问题纠结了我很久,最好找到解决方法,这里分享一下,希望大家不要再受这种困惑.解决方法: 点击工程右键->properties-&g ...

  7. 第十一篇:SOUI系统资源管理

    SOUI资源管理模块 从前篇已经讲到在SOUI中所有资源文件通过一个uires.idx文件进行索引. 这里将介绍在程序中如何引用这些资源文件. 在SOUI系统中,资源文件通过一个统一的接口对象读取: ...

  8. [Unity3d插件]EasyTouch的初步使用

    对于移动平台上的RPG类的游戏,我们常用虚拟摇杆来控制人物角色的行走和一些行为,相信我们对它并不陌生,之前尝试了EasyTouch2.5,发现并没有最新版的3.1好用,2.5版本的对于自适应没有做的很 ...

  9. Json转换利器Gson之实例一-简单对象转化和带泛型的List转化 (转)

    Gson 是 Google 提供的用来在 Java 对象和 JSON 数据之间进行映射的 Java 类库.可以将一个 JSON 字符串转成一个 Java 对象,或者反过来. jar和源码下载地址: h ...

  10. C#联通新版验证码识别的实现

    以前写了篇 联通充值卡自动充值的实现,最近发现联通官网改版了,随便看了下发现新版的验证码和以前的不同,发了点时间研究了下他的识别码,它现在的验证码如下 现在将识别步骤说下 1,转换灰度图片 2,清除2 ...