题目大意:

  有一个长度为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. Thinkphp3.2中的模板继承

    1:模板继承:   是3.1.2版本添加的一项更加灵活的模板布局方式,模板继承不同于模板布局,甚至来说,应该在模板布局的上层.模板继承其实并不难理解,就好比 类的继承一样,模板也可以定义一个基础模板( ...

  2. Linux环境下使用C/C++编写CGI(httpd)

    step1下载: ftp://ftp.gnu.org/gnu/cgicc/ step2: tar xzf cgicc-X.X.X.tar.gz(用最新版本) cd cgicc-X.X.X ./conf ...

  3. android 入门-git之上传本地代码到github

    github部分: 1.首先去github网站 上注册一个用户 2.说明 https://guides.github.com/activities/hello-world/ 2.点击 New repo ...

  4. 限制非安全IP访问

    这个是一个检测ip是否非法的php函数,适应于白名单,黑名单功能开发,主要场景应用于:api来源限制,访问限制等. /** * 安全IP检测,支持IP段检测 * @param string $ip 要 ...

  5. AgileEAS.NET SOA 中间件平台5.2版本下载、配置学习(二):配置WinClient分布式运行环境

    一.前言 AgileEAS.NET SOA 中间件平台是一款基于基于敏捷并行开发思想和Microsoft .Net构件(组件)开发技术而构建的一个快速开发应用平台.用于帮助中小型软件企业建立一条适合市 ...

  6. [荐]jquery插件开发入门

    http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html $.fn.myPlugin = function() { //在这里面,this指 ...

  7. 如何设计一个优秀的API(转)

    到目前为止,已经负责API接近两年了,这两年中发现现有的API存在的问题越来越多,但很多API一旦发布后就不再能修改了,即时升级和维护是必须的.一旦API发生变化,就可能对相关的调用者带来巨大的代价, ...

  8. 用js实现图片自动加载的瀑布流效果

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  9. JSHint配置详解

    Also available on Github JSHint配置详解 增强参数(Enforcing Options) 本类参数设为true,JSHint会产生更多告警. bitwise 禁用位运算符 ...

  10. css学习(2)-- 常见的CSS属性和值

    1.CSS中修饰字体的属性 属    性 描    述 属  性  值 font-family 字体族科 任意字体族科名称都可以使用例如Times.serif等,而且多个族科的赋值是可以使用的,中间用 ...