CF446C题意:

给你一个数列\(a_i\),有两种操作:区间求和;\(\sum_{i=l}^{r}(a[i]+=fib[i-l+1])\)。\(fib\)是斐波那契数列。

思路

(一)

codeforces 447E or 446C

\(fib[n] = \frac{\sqrt5}{5}\times [(\frac{1+\sqrt5}{2})^n-(\frac{1-\sqrt5}{2})^n]\)

有关取模、同余、逆元的一些东西:

\(p = 1e9 + 9\)

\(383008016^2 ≡ 5 (mod\;p)\)

\(383008016 ≡ \sqrt5 (mod\;p)\)

\(\frac{1}{\sqrt5}≡276601605(mod\;p)\)

\(383008016的逆元 = 276601605\)

\((1+\sqrt5)/2≡691504013(mod\;p)\)

\(383008017\times 2的逆元 = 691504013\)

\((1-\sqrt5)/2≡308495997(mod\;p)\)

\((p-383008016+1)\times 2的逆元 = 308495997\)

\(fib[n] = 276601605\times [(691504013)^n-(308495997)^n] (mod\;\;p)\)

等比数列求和:\(sum = \frac{a}{a-1} \times (a^n - 1) (mod\;\;p) = a^2(a^n-1)(mod\;\;p)=a^{n+2}-a^2(mod\;\;p)\)

当\(p=1e9+9, a = 691504013或308495997时成立\)。

所以本题我们只需要用线段树lazy标记维护两个等比数列第一项为一次项的系数即可。代码如下。

  1. #include<bits/stdc++.h>
  2. #define lson rt<<1
  3. #define rson rt<<1|1
  4. using namespace std;
  5. typedef long long LL;
  6. const int MXN = 5e5 + 6;
  7. const int INF = 0x3f3f3f3f;
  8. const LL mod = 1000000009;
  9. const LL p1 = 691504013;
  10. const LL p2 = 308495997;
  11. const LL p3 = 276601605;
  12. int n, m;
  13. LL ar[MXN], pre[MXN], mul1[MXN], mul2[MXN];
  14. LL sum[MXN<<2], lazy1[MXN<<2], lazy2[MXN<<2];
  15. LL ksm(LL a, LL b) {
  16. LL res = 1;
  17. for(;b;b>>=1,a=a*a%mod) {
  18. if(b&1) res = res * a %mod;
  19. }
  20. return res;
  21. }
  22. void check(LL &a) {
  23. if(a >= mod) a %= mod;
  24. }
  25. void push_up(int rt) {
  26. sum[rt] = sum[lson] + sum[rson]; check(sum[rt]);
  27. }
  28. void push_down(int l,int r,int rt) {
  29. if(lazy1[rt] == 0 && lazy2[rt] == 0) return;
  30. LL a = lazy1[rt], b = lazy2[rt];
  31. int mid = (l + r) >> 1;
  32. int len1 = mid-l+1, len2 = r - mid;
  33. lazy1[lson] += a; lazy2[lson] += b;
  34. sum[lson] = sum[lson] + a*((mul1[len1+2]-mul1[2])%mod+mod); check(sum[lson]);
  35. sum[lson] = (sum[lson] - b*((mul2[len1+2]-mul2[2])%mod+mod))%mod + mod; check(sum[lson]);
  36. lazy1[rson] += a*mul1[len1]%mod; lazy2[rson] += b*mul2[len1]%mod;
  37. sum[rson] = sum[rson] + a*mul1[len1]%mod*((mul1[len2+2]-mul1[2])%mod+mod); check(sum[rson]);
  38. sum[rson] = (sum[rson] - b*mul2[len1]%mod*((mul2[len2+2]-mul2[2])%mod+mod))%mod + mod; check(sum[rson]);
  39. lazy1[rt] = lazy2[rt] = 0;
  40. check(lazy1[lson]);check(lazy1[rson]);check(lazy2[lson]);check(lazy2[rson]);
  41. }
  42. void update(int L,int R,int l,int r,int rt,LL x,LL y) {
  43. if(L <= l && r <= R) {
  44. lazy1[rt] += x; lazy2[rt] += y;
  45. check(lazy1[rt]); check(lazy2[rt]);
  46. sum[rt] = sum[rt] + x*((mul1[r-l+3]-mul1[2])%mod+mod); check(sum[rt]);
  47. sum[rt] = (sum[rt] - y*((mul2[r-l+3]-mul2[2])%mod+mod))%mod + mod; check(sum[rt]);
  48. return;
  49. }
  50. push_down(l, r, rt);
  51. int mid = (l + r) >> 1;
  52. if(L > mid) update(L,R,mid+1,r,rson,x,y);
  53. else if(R <= mid) update(L,R,l,mid,lson,x,y);
  54. else {
  55. update(L,mid,l,mid,lson,x,y);
  56. update(mid+1,R,mid+1,r,rson,mul1[mid-L+1]*x%mod,mul2[mid-L+1]*y%mod);
  57. }
  58. push_up(rt);
  59. }
  60. LL query(int L,int R,int l,int r,int rt) {
  61. if(L <= l && r <= R) {
  62. return sum[rt];
  63. }
  64. push_down(l,r,rt);
  65. int mid = (l+r) >> 1;
  66. if(L > mid) return query(L,R,mid+1,r,rson);
  67. else if(R <= mid) return query(L,R,l,mid,lson);
  68. else {
  69. LL ans = query(L,mid,l,mid,lson);
  70. ans += query(mid+1,R,mid+1,r,rson);
  71. check(ans);
  72. return ans;
  73. }
  74. }
  75. int main() {
  76. //printf("%d\n", ksm(691504013-1,mod-2));
  77. //printf("%d\n", ksm(308495997-1,mod-2));
  78. //F(n) = √5/5[((1+√5)/2)^n-((1-√5)/2)^n]
  79. //383008016^2 ≡ 5 (mod 1e9 + 9)
  80. //383008016 ≡ sqrt(5) (mod 1e9 + 9)
  81. //printf("%lld\n", ksm(383008016,mod-2));//1/sqrt(5)≡276601605(mod)
  82. //printf("%lld\n", 383008017*ksm(2,mod-2)%mod);//(1+sqrt(5))/2≡691504013(mod)
  83. //printf("%lld\n", (mod-383008016+1)*ksm(2,mod-2)%mod);//(1-sqrt(5))/2≡308495997(mod)
  84. scanf("%d%d", &n, &m);
  85. mul1[0] = mul2[0] = 1;
  86. for(int i = 1; i < 301000; ++i) {
  87. mul1[i] = mul1[i-1] * p1;
  88. mul2[i] = mul2[i-1] * p2;
  89. check(mul1[i]); check(mul2[i]);
  90. }
  91. for(int i = 1; i <= n; ++i) scanf("%lld", &ar[i]), pre[i] = (pre[i-1] + ar[i])%mod;
  92. while(m --) {
  93. int opt, l, r;
  94. scanf("%d%d%d", &opt, &l, &r);
  95. if(opt == 1) {
  96. update(l, r, 1, n, 1, 1, 1);
  97. }else {
  98. printf("%lld\n", ((p3*query(l,r,1,n,1)%mod+pre[r]-pre[l-1])%mod+mod)%mod);
  99. }
  100. }
  101. return 0;
  102. }

(二)

斐波纳契数列的一些性质:



性质1:对于一个满足斐波那契性质的数列,如果我们已知它的前两项,我们可以O(1)的得到它的任意一项和任意前缀和!

性质2:两个满足斐波那契性质的数列相加后,依然是斐波那契数列。前两项的值分别为两个的和。

所以本题我们用线段树的\(lazy\)标记维护给这个区间各项加上的\(fib\)数列的前两项的值。通过这个\(lazy\)标记我们可以\(O(1)\)更新区间和,因为斐波纳契数列满足可加性,所以我们\(lazy\)标记也可以很轻松的\(push\_down\)操作。代码如下。

  1. #include<bits/stdc++.h>
  2. #define lson rt<<1
  3. #define rson rt<<1|1
  4. using namespace std;
  5. typedef long long LL;
  6. const int MXN = 5e5 + 6;
  7. const int INF = 0x3f3f3f3f;
  8. const LL mod = 1000000009;
  9. const LL p1 = 691504013;
  10. const LL p2 = 308495997;
  11. const LL p3 = 276601605;
  12. int n, m;
  13. LL ar[MXN], fib[MXN];
  14. LL sum[MXN<<2], lazy1[MXN<<2], lazy2[MXN<<2];
  15. LL ksm(LL a, LL b) {
  16. LL res = 1;
  17. for(;b;b>>=1,a=a*a%mod) {
  18. if(b&1) res = res * a %mod;
  19. }
  20. return res;
  21. }
  22. LL hn(int n,LL a,LL b) {
  23. if(n == 1) return (a%mod+mod)%mod;
  24. if(n == 2) return (b%mod+mod)%mod;
  25. return ((a*fib[n-2] + b*fib[n-1])%mod+mod)%mod;
  26. }
  27. void check(LL &a) {
  28. if(a >= mod) a %= mod;
  29. }
  30. void push_up(int rt) {
  31. sum[rt] = sum[lson] + sum[rson]; check(sum[rt]);
  32. }
  33. void build(int l,int r,int rt) {
  34. if(l == r) {
  35. sum[rt] = ar[l];
  36. return;
  37. }
  38. int mid = (l + r) >> 1;
  39. build(l, mid, lson); build(mid+1, r, rson);
  40. push_up(rt);
  41. }
  42. void push_down(int l,int r,int rt) {
  43. if(lazy1[rt] == 0 && lazy2[rt] == 0) return;
  44. LL a = lazy1[rt], b = lazy2[rt];
  45. int mid = (l + r) >> 1;
  46. int len1 = mid-l+1, len2 = r - mid;
  47. lazy1[lson] += a; lazy2[lson] += b;
  48. sum[lson] = (sum[lson] + hn(len1+2,a,b) - b)%mod+mod;
  49. lazy1[rson] += hn(len1+1,a,b); lazy2[rson] += hn(len1+2,a,b);
  50. sum[rson] = (sum[rson] + hn(len2+2,hn(len1+1,a,b),hn(len1+2,a,b))-hn(len1+2,a,b))%mod+mod;
  51. check(sum[lson]); check(sum[rson]);
  52. check(lazy1[lson]);check(lazy1[rson]);check(lazy2[lson]);check(lazy2[rson]);
  53. lazy1[rt] = lazy2[rt] = 0;
  54. }
  55. void update(int L,int R,int l,int r,int rt,LL x, LL y) {
  56. if(L <= l && r <= R) {
  57. lazy1[rt] += x; lazy2[rt] += y;
  58. check(lazy1[rt]); check(lazy2[rt]);
  59. sum[rt] = (sum[rt] + hn(r-l+1+2,x,y) - y)%mod+mod; check(sum[rt]);
  60. return;
  61. }
  62. push_down(l, r, rt);
  63. int mid = (l + r) >> 1;
  64. if(L > mid) update(L,R,mid+1,r,rson,x,y);
  65. else if(R <= mid) update(L,R,l,mid,lson,x,y);
  66. else {
  67. update(L,mid,l,mid,lson,x,y);
  68. update(mid+1,R,mid+1,r,rson,hn(mid-L+1+1,x,y), hn(mid-L+1+2,x,y));
  69. }
  70. push_up(rt);
  71. }
  72. LL query(int L,int R,int l,int r,int rt) {
  73. if(L <= l && r <= R) {
  74. return sum[rt];
  75. }
  76. push_down(l,r,rt);
  77. int mid = (l+r) >> 1;
  78. if(L > mid) return query(L,R,mid+1,r,rson);
  79. else if(R <= mid) return query(L,R,l,mid,lson);
  80. else {
  81. LL ans = query(L,mid,l,mid,lson);
  82. ans += query(mid+1,R,mid+1,r,rson);
  83. check(ans);
  84. return ans;
  85. }
  86. }
  87. int main() {
  88. scanf("%d%d", &n, &m);
  89. fib[1] = fib[2] = 1;
  90. for(int i = 3; i < 301000; ++i) {
  91. fib[i] = fib[i-1] + fib[i-2];
  92. check(fib[i]);
  93. }
  94. for(int i = 1; i <= n; ++i) scanf("%lld", &ar[i]);
  95. build(1, n, 1);
  96. while(m --) {
  97. int opt, l, r;
  98. scanf("%d%d%d", &opt, &l, &r);
  99. if(opt == 1) {
  100. update(l, r, 1, n, 1, 1, 1);
  101. }else {
  102. printf("%lld\n", query(l,r,1,n,1));
  103. }
  104. }
  105. return 0;
  106. }

codeforces 447E or 446C 线段树 + fib性质或二次剩余性质的更多相关文章

  1. [Codeforces 316E3]Summer Homework(线段树+斐波那契数列)

    [Codeforces 316E3]Summer Homework(线段树+斐波那契数列) 顺便安利一下这个博客,给了我很大启发(https://gaisaiyuno.github.io/) 题面 有 ...

  2. Buses and People CodeForces 160E 三维偏序+线段树

    Buses and People CodeForces 160E 三维偏序+线段树 题意 给定 N 个三元组 (a,b,c),现有 M 个询问,每个询问给定一个三元组 (a',b',c'),求满足 a ...

  3. CodeForces 877E DFS序+线段树

    CodeForces 877E DFS序+线段树 题意 就是树上有n个点,然后每个点都有一盏灯,给出初始的状态,1表示亮,0表示不亮,然后有两种操作,第一种是get x,表示你需要输出x的子树和x本身 ...

  4. [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路)

    [Codeforces 1197E]Culture Code(线段树优化建图+DAG上最短路) 题面 有n个空心物品,每个物品有外部体积\(out_i\)和内部体积\(in_i\),如果\(in_i& ...

  5. [Codeforces 1199D]Welfare State(线段树)

    [Codeforces 1199D]Welfare State(线段树) 题面 给出一个长度为n的序列,有q次操作,操作有2种 1.单点修改,把\(a_x\)修改成y 2.区间修改,把序列中值< ...

  6. Codeforces 482B Interesting Array(线段树)

    题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,如今有M个限制,每一个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 ...

  7. Codeforces 1083C Max Mex [线段树]

    洛谷 Codeforces 思路 很容易发现答案满足单调性,可以二分答案. 接下来询问就转换成判断前缀点集是否能组成一条链. 我最初的想法:找到点集的直径,判断直径是否覆盖了所有点,需要用到树套树,复 ...

  8. Codeforces 1132G Greedy Subsequences [线段树]

    洛谷 Codeforces 看到题解那么少就来发一篇吧-- 思路 看完题目一脸懵逼,感觉无从下手. 莫名其妙地想到笛卡尔树,但笛卡尔树好像并没有太大作用. 考虑把笛卡尔树改一下:每个点的父亲设为它的右 ...

  9. Codeforces Gym 100231B Intervals 线段树+二分+贪心

    Intervals 题目连接: http://codeforces.com/gym/100231/attachments Description 给你n个区间,告诉你每个区间内都有ci个数 然后你需要 ...

随机推荐

  1. linux之-mysql数据库约束3

    在MySQL中,通常有这几种约束: DROP DATABASE mysql_shiyan;删除数据库 主键 (PRIMARY KEY)是用于约束表中的一行,作为这一行的唯一标识符,在一张表中通过主键就 ...

  2. Django的流程如何理解(餐厅点餐举例)

    去饭店(商场)吃饭的步骤: 告诉前台服务员,来一小碗牛肉拉面,菜单上勾上一个牛肉拉面(url) 服务员去拉面窗口,告诉后厨,一碗牛肉拉面),后厨(view)开始准备. 后厨给打杂小弟说,给我一份儿面条 ...

  3. cs224d 作业 problem set3 (一) 实现Recursive Nerual Net Work 递归神经网络

    1.Recursive Nerual Networks能够更好地体现每个词与词之间语法上的联系这里我们选取的损失函数仍然是交叉熵函数 2.整个网络的结构如下图所示: 每个参数的更新时的梯队值如何计算, ...

  4. 用processing画李萨如曲线

    李萨如曲线 有没有对示波器上变化曲线产生过兴趣,它叫做李萨如曲线: 数学上,利萨茹(Lissajous)曲线(又称利萨茹图形.李萨如图形或鲍迪奇(Bowditch)曲线)是两个沿着互相垂直方向的正弦振 ...

  5. PAT_A1097#Deduplication on a Linked List

    Source: PAT A1097 Deduplication on a Linked List (25 分) Description: Given a singly linked list L wi ...

  6. 分布式ID生成器的解决方案总结

    在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID.退款ID等.那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决方案是十分重要 ...

  7. java虚拟机规范(se8)——java虚拟机的编译(一)

    本文翻译自:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html 第三章 java虚拟机的编译 java虚拟机是设计用来支持ja ...

  8. go strconv

    strconv是golang用来做数据类型转换的一个库. 介绍下strconv最常用的两个方法, 没有解释语言那么自在可以str(int),int(string), 那还算简练. num, err : ...

  9. 服务bindService()方法启动服务

    public class MainActivity extends Activity { private EditText studentno; private ServiceConnection c ...

  10. iOS开发系列-Block

    概述 在iOS 4.0之后,block横空出世,它本身封装了一段代码并将这段代码当做变量,通过block()的方式进行回调.这不免让我们想到在C函数中,我们可以定义一个指向函数的指针并且调用. #im ...