2962: 序列操作

Time Limit: 50 Sec  Memory Limit: 256 MB
Submit: 1145  Solved: 378
[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

分析:线段树套路题.类似:传送门,这类题有一个特征就是需要维护的东西比较少:c <= 20,那么就可以开一个数组分别维护这些东西.
          f[i]表示当前区间选i个数相乘的和,显然一开始f[1] = a[pos].合并的时候f[i] = 左子树的f[i] + 右子树的f[i] + 左子树的f[j] * 右子树的f[k],j+k = i. 考虑两个修改操作对答案的影响.取反操作比较简单,注意到当i是奇数时f[i]才会变号.注意,取反以后一定要通过加上模数取模来变成正数.
          第一个操作有点鬼畜.纸上写几个例子,拆项后会再合并,就差不多能发现规律:,感性理解一下就是c的k次方,c要占k个位置,而另外的位置已经被f选的数给占了,只能在剩下的位置中选c,这大概就是组合数的意义.剩下的都可以通过合并同类项得到.
       一些细节需要注意,比如取反后一定要变成正数再来运算,f[0]一定要强制等于1,用类进行运算一定要先初始化,第一个操作对于f的处理要倒序处理,这些在之前附上链接的那道题中都有体现.
     总之,都是套路啦.
  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. typedef long long ll;
  9. const ll maxn = ,mod = ;
  10. ll n,q;
  11. ll a[maxn],c[maxn][];
  12.  
  13. struct node
  14. {
  15. ll add,cover,f[],L,R;
  16. void init()
  17. {
  18. add = cover = L = R = ;
  19. memset(f,,sizeof(f));
  20. f[] = ;
  21. }
  22. } e[maxn << ];
  23.  
  24. node pushup(node a,node b)
  25. {
  26. node c;
  27. c.init();
  28. c.L = a.L;
  29. c.R = b.R;
  30. ll len1 = c.R - c.L + ;
  31. ll len2 = a.R - a.L + ;
  32. ll len3 = b.R - b.L + ;
  33. for (ll i = ; i <= min(len2,1LL * ); i++)
  34. for (ll j = ; j <= min(len3,1LL * ); j++)
  35. {
  36. if (i + j > )
  37. break;
  38. c.f[i + j] = (c.f[i + j] + a.f[i] * b.f[j] % mod) % mod;
  39. }
  40. c.f[] = ; //易错点
  41. return c;
  42. }
  43.  
  44. void fan(ll o)
  45. {
  46. ll len = e[o].R - e[o].L + ;
  47. for (ll i = ; i <= min(len,1LL * ); i++)
  48. {
  49. if (i % == )
  50. {
  51. e[o].f[i] = -e[o].f[i];
  52. e[o].f[i] = (e[o].f[i] + mod) % mod;
  53. }
  54. }
  55. e[o].cover ^= ;
  56. e[o].add = -e[o].add;
  57. e[o].add = (e[o].add + mod) % mod; //取反后一定要变成正数
  58. }
  59.  
  60. void jia(ll o,ll v)
  61. {
  62. ll len = e[o].R - e[o].L + ;
  63. for (ll i = min(len,1LL * );i >= ; i--) //一定要倒着推
  64. {
  65. ll k = v;
  66. for (ll j = i - ; j >= ; j--)
  67. {
  68. e[o].f[i] = (e[o].f[i] + e[o].f[j] * c[len - j][i - j] % mod * k % mod) % mod;
  69. k = k * v % mod;
  70. }
  71. }
  72. e[o].add = (e[o].add + v) % mod;
  73. }
  74.  
  75. void pushdown(ll o)
  76. {
  77. if (e[o].cover)
  78. {
  79. fan(o * );
  80. fan(o * + );
  81. e[o].cover = ;
  82. }
  83. if (e[o].add)
  84. {
  85. jia(o * ,e[o].add);
  86. jia(o * + ,e[o].add);
  87. e[o].add = ;
  88. }
  89. }
  90.  
  91. void build(ll o,ll l,ll r)
  92. {
  93. e[o].init();
  94. e[o].L = l,e[o].R = r;
  95. if (l == r)
  96. {
  97. e[o].f[] = a[l] % mod;
  98. return;
  99. }
  100. ll mid = (l + r) >> ;
  101. build(o * ,l,mid);
  102. build(o * + ,mid + ,r);
  103. e[o] = pushup(e[o * ],e[o * + ]);
  104. }
  105.  
  106. void update1(ll o,ll l,ll r,ll x,ll y,ll v)
  107. {
  108. if (x <= l && r <= y)
  109. {
  110. jia(o,v);
  111. return;
  112. }
  113. pushdown(o);
  114. ll mid = (l + r) >> ;
  115. if (x <= mid)
  116. update1(o * ,l,mid,x,y,v);
  117. if (y > mid)
  118. update1(o * + ,mid + ,r,x,y,v);
  119. e[o] = pushup(e[o * ],e[o * + ]);
  120. }
  121.  
  122. void update2(ll o,ll l,ll r,ll x,ll y)
  123. {
  124. if (x <= l && r <= y)
  125. {
  126. fan(o);
  127. return;
  128. }
  129. pushdown(o);
  130. ll mid = (l + r) >> ;
  131. if (x <= mid)
  132. update2(o * ,l,mid,x,y);
  133. if (y > mid)
  134. update2(o * + ,mid + ,r,x,y);
  135. e[o] = pushup(e[o * ],e[o * + ]);
  136. }
  137.  
  138. node query(ll o,ll l,ll r,ll x,ll y)
  139. {
  140. if (x <= l && r <= y)
  141. return e[o];
  142. pushdown(o);
  143. ll mid = (l + r) >> ;
  144. if (y <= mid)
  145. return query(o * ,l,mid,x,y);
  146. else if (x > mid)
  147. return query(o * + ,mid + ,r,x,y);
  148. else
  149. return pushup(query(o * ,l,mid,x,mid),query(o * + ,mid + ,r,mid + ,y));
  150. }
  151.  
  152. int main()
  153. {
  154. scanf("%lld%lld",&n,&q);
  155. c[][] = ;
  156. for (ll i = ; i <= n; i++)
  157. {
  158. c[i][] = ;
  159. for (ll j = ; j <= ; j++)
  160. c[i][j] = (c[i - ][j] + c[i - ][j - ]) % mod;
  161. }
  162. for (ll i = ; i <= n; i++)
  163. scanf("%lld",&a[i]);
  164. build(,,n);
  165. while (q--)
  166. {
  167. char ch[];
  168. ll a,b,c;
  169. scanf("%s",ch);
  170. if (ch[] == 'I')
  171. {
  172. scanf("%lld%lld%lld",&a,&b,&c);
  173. update1(,,n,a,b,c);
  174. }
  175. if (ch[] == 'R')
  176. {
  177. scanf("%lld%lld",&a,&b);
  178. update2(,,n,a,b);
  179. }
  180. if (ch[] == 'Q')
  181. {
  182. scanf("%lld%lld%lld",&a,&b,&c);
  183. node temp = query(,,n,a,b);
  184. printf("%lld\n",temp.f[c] % mod);
  185. }
  186. }
  187.  
  188. return ;
  189. }

bzoj2962 序列操作的更多相关文章

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

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

  2. bzoj2962 序列操作 题解

    题目大意: 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反数,3.Q a b c表示询问[a,b]这 ...

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

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

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

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

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

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

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

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

  7. Python通用序列操作

    1.序列概览 1.数据结构 序列.容器 Python中最基本的数据结构是序列,其有索引(从左到右第一个索引为0,从右到左第一个索引为-1). Python包含6中内建的序列: 列表 元组 字符串 Un ...

  8. 【BZOJ-1858】序列操作 线段树

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1961  Solved: 991[Submit][Status ...

  9. bzoj 1858: [Scoi2010]序列操作

    1858: [Scoi2010]序列操作 Time Limit: 10 Sec  Memory Limit: 64 MB 线段树,对于每个区间需要分别维护左右和中间的1和0连续个数,并在op=4时特殊 ...

随机推荐

  1. 数据库sql优化总结之2-百万级数据库优化方案+案例分析

    项目背景 有三张百万级数据表 知识点表(ex_subject_point)9,316条数据 试题表(ex_question_junior)2,159,519条数据 有45个字段 知识点试题关系表(ex ...

  2. 使用MyBatis遇到的一些需要记录下的问题

    (1)MyBaits结果集返回Map,Map集合乱序. xml 中的SQL 输出: 改成: 输出: 目测跟字母顺序有关:ABCDEFGHIJKLMNOPQRSTUVWXYZ (2)需要对字段动态排序 ...

  3. OpenLDAP编译安装及配置

    原文发表于cu:2016-06-20 参考文档: 原理:http://seanlook.com/2015/01/15/openldap_introduction/ 官方文档: http://www.o ...

  4. 228. [LeetCode] Summary Ranges

    Given a sorted integer array without duplicates, return the summary of its ranges. Example 1: Input: ...

  5. CDQ分治_占坑

    准备系统地学习一波CDQ分治,持续更新中... 首先,CDQ分治也还是分治的一种,只不过普通分治是独立的解决两个子问题,而CDQ分治还要计算第一个子问题对于第二个的影响. CDQ分治几乎都是用来解决多 ...

  6. leetcode个人题解——#43 Multiply Strings

    思路:高精度乘法就可以了. 有两个错误以前没在意,1.成员属性定义时候不能进行初始化, vector<); 这样隐性调用了函数进行初始化的形式特别要注意,也是错误的: 2.容器类只有分配了空间时 ...

  7. AJAX请求.net controller数据交互过程

    AJAX发出请求 $.ajax({ url: "/Common/CancelTaskDeal", //CommonController下的CancelTaskDeal方法 type ...

  8. oracle执行完shutdown immediate后登陆不上了怎么办

    在sqlplus 里登录后使用shutdown immediate 关闭数据库后若没有使用startup重启数据库就退出窗口则会出现下一次重启sqlplus窗口时无法登录的现象,解决方法如下 一.启动 ...

  9. VC++调试基础

    一.调试基础 调试快捷键 F5:  开始调试 Shift+F5: 停止调试 F10:   调试到下一句,这里是单步跟踪 F11:   调试到下一句,跟进函数内部 Shift+F11:  从当前函数中跳 ...

  10. 对小组项目alpha发布的评价

    第一组:新蜂小组 项目:俄罗斯方块 评论:看见同学玩的时候,感到加速下落时不是很灵敏,没有及成绩的功能,用户的界面仍在修正. 第二组:天天向上 项目:连连看 评论:这个游戏增加了很多好玩的功能,比如更 ...