zoukankan      html  css  js  c++  java
  • codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)

    In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation

    F1 = 1; F2 = 1; Fn = Fn - 1 + Fn - 2 (n > 2).

    DZY loves Fibonacci numbers very much. Today DZY gives you an array consisting of n integers: a1, a2, ..., an. Moreover, there are mqueries, each query has one of the two types:

    1. Format of the query "l r". In reply to the query, you need to add Fi - l + 1 to each element ai, where l ≤ i ≤ r.
    2. Format of the query "l r". In reply to the query you should output the value of  modulo 1000000009 (109 + 9).

    Help DZY reply to all the queries.

    Input

    The first line of the input contains two integers n and m (1 ≤ n, m ≤ 300000). The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109) — initial array a.

    Then, m lines follow. A single line describes a single query in the format given in the statement. It is guaranteed that for each query inequality 1 ≤ l ≤ r ≤ n holds.

    Output

    For each query of the second type, print the value of the sum on a single line.

    题目大意:维护一个序列,每次给一段序列加上一个斐波那契数列,或者询问一段序列的和。

    思路1:两个斐波那契的定理,用数学归纳法很容易证明:

    ①定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3)。有F[n] = b * fib[n - 1] + a * fib[n - 2](n≥3),其中fib[i]为斐波那契数列的第 i 项。

    ②定义F[1] = a, F[2] = b, F[n] = F[n - 1] + F[n - 2](n≥3)。有F[1] + F[2] + …… + F[n] = F[n + 2] - b。

    这题还有一个事实,就是两个上述定义的数列,相加,仍然符合F[n] = F[n - 1] + F[n - 2]的递推公式。

    利用这两个定理,用线段树维护序列,线段树的每个结点记录这一段的前两项是什么,预处理好斐波那契数列,便能O(1)地计算出每一个结点中间的数是多少、每一个结点的和。

    代码(1513MS):

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstring>
     4 #include <cstdio>
     5 #include <cmath>
     6 using namespace std;
     7 typedef long long LL;
     8 #define ll (x << 1)
     9 #define rr ((x << 1) | 1)
    10 #define mid ((l + r) >> 1)
    11 
    12 const int MOD = 1e9 + 9;
    13 
    14 const int MAXN = 300010;
    15 const int MAXT = MAXN << 2;
    16 
    17 int f1[MAXT], f2[MAXT], sum[MAXT];
    18 int a[MAXN], fib[MAXN];
    19 int n, m;
    20 
    21 void init() {
    22     fib[1] = fib[2] = 1;
    23     for(int i = 3; i <= n + 2; ++i) {
    24         fib[i] = fib[i - 1] + fib[i - 2];
    25         if(fib[i] >= MOD) fib[i] -= MOD;
    26     }
    27 }
    28 
    29 int get_fib(int a, int b, int n) {
    30     if(n == 1) return a;
    31     if(n == 2) return b;
    32     return (LL(b) * fib[n - 1] + LL(a) * fib[n - 2]) % MOD;
    33 }
    34 
    35 int get_sum(int a, int b, int n) {
    36     return (get_fib(a, b, n + 2) - b + MOD) % MOD;
    37 }
    38 
    39 void add_fib(int x, int l, int r, int a, int b) {
    40     (f1[x] += a) %= MOD;
    41     (f2[x] += b) %= MOD;
    42     (sum[x] += get_sum(a, b, r - l + 1)) %= MOD;
    43 }
    44 
    45 void pushdown(int x, int l, int r) {
    46     add_fib(ll, l, mid, f1[x], f2[x]);
    47     add_fib(rr, mid + 1, r, get_fib(f1[x], f2[x], mid + 1 - l + 1), get_fib(f1[x], f2[x], mid + 2 - l + 1));
    48     f1[x] = f2[x] = 0;
    49 }
    50 
    51 void maintain(int x) {
    52     sum[x] = (sum[ll] + sum[rr]) % MOD;
    53 }
    54 
    55 void build(int x, int l, int r) {
    56     if(l == r) {
    57         sum[x] = a[l];
    58     } else {
    59         build(ll, l, mid);
    60         build(rr, mid + 1, r);
    61         maintain(x);
    62     }
    63 }
    64 
    65 void update(int x, int l, int r, int a, int b) {
    66     if(a <= l && r <= b) {
    67         add_fib(x, l, r, fib[l - a + 1], fib[l + 1 - a + 1]);
    68     } else {
    69         pushdown(x, l, r);
    70         if(a <= mid) update(ll, l, mid, a, b);
    71         if(mid < b) update(rr, mid + 1, r, a, b);
    72         maintain(x);
    73     }
    74 }
    75 
    76 int query(int x, int l, int r, int a, int b) {
    77     if(a <= l && r <= b) {
    78         return sum[x];
    79     } else {
    80         int ret = 0;
    81         pushdown(x, l, r);
    82         if(a <= mid) (ret += query(ll, l, mid, a, b)) %= MOD;
    83         if(mid < b) (ret += query(rr, mid + 1, r, a, b)) %= MOD;
    84         return ret;
    85     }
    86 }
    87 
    88 int main() {
    89     scanf("%d%d", &n, &m);
    90     for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    91     init();
    92     build(1, 1, n);
    93     int op, l, r;
    94     while(m--) {
    95         scanf("%d%d%d", &op, &l, &r);
    96         if(op == 1) update(1, 1, n, l, r);
    97         if(op == 2) printf("%d
    ", query(1, 1, n, l, r));
    98     }
    99 }
    View Code

    思路2:按官方题解的说法,有通项公式$ fib_n = frac{ sqrt 5 } 5 * (( frac {1 + sqrt 5} 2) ^ n - ( frac {1 - sqrt 5} 2) ^ n) $。

    5是1e9+9的二次剩余,383008016^2=5(mod 1e9+9)。

    利用逆元,可计算出:$ frac {sqrt 5} 5、frac {1 + sqrt 5} 2、 frac {1 - sqrt 5} 2 $在模1e9+9意义下的值。

    然后,变成用线段树维护两个等比数列。预处理出$frac {1 + sqrt 5} 2$和$frac {1 - sqrt 5} 2$的1~n的次方的值,设他们为q,还要求出1-q的逆元(用于计算等比数列的和)。

    线段树每个结点记录两个等比数列的首项,跟上面的方法差不多,也是这样维护一个线段树即可。

    代码(1996MS):

      1 #include <iostream>
      2 #include <algorithm>
      3 #include <cstring>
      4 #include <cstdio>
      5 #include <cmath>
      6 using namespace std;
      7 typedef long long LL;
      8 #define ll (x << 1)
      9 #define rr ((x << 1) | 1)
     10 #define mid ((l + r) >> 1)
     11 
     12 const int MOD = 1e9 + 9;
     13 const int SQRT5 = 383008016;
     14 
     15 const int MAXN = 300010;
     16 const int MAXT = MAXN << 2;
     17 
     18 int powa[MAXN], powb[MAXN];
     19 int coe, ta, tb, invta, invtb;
     20 int fa[MAXT], fb[MAXT], sum[MAXT];
     21 int a[MAXN];
     22 int n, m;
     23 
     24 int inv(int x) {
     25     if(x == 1) return 1;
     26     return (LL(MOD - MOD / x) * inv(MOD % x)) % MOD;
     27 }
     28 
     29 void init() {
     30     coe = inv(SQRT5);
     31     ta = (LL(1 + SQRT5) * inv(2)) % MOD;
     32     tb = (LL(1 - SQRT5 + MOD) * inv(2)) % MOD;
     33     invta = inv(1 - ta + MOD);
     34     invtb = inv(1 - tb + MOD);
     35     //cout<<coe<<endl<<ta<<endl<<tb<<endl;
     36     powa[0] = powb[0] = 1;
     37     for(int i = 1; i <= n; ++i) {
     38         powa[i] = LL(powa[i - 1]) * ta % MOD;
     39         powb[i] = LL(powb[i - 1]) * tb % MOD;
     40     }
     41 }
     42 
     43 void maintain(int x) {
     44     sum[x] = (sum[ll] + sum[rr]) % MOD;
     45 }
     46 
     47 void add_fib(int x, int l, int r, int a, int b) {
     48     (fa[x] += a) %= MOD;
     49     (fb[x] += b) %= MOD;
     50     (sum[x] += LL(a) * (1 - powa[r - l + 1] + MOD) % MOD * invta % MOD) %= MOD;
     51     (sum[x] -= LL(b) * (1 - powb[r - l + 1] + MOD) % MOD * invtb % MOD) %= MOD;
     52     if(sum[x] < 0) sum[x] += MOD;
     53 }
     54 
     55 void pushdown(int x, int l, int r) {
     56     add_fib(ll, l, mid, fa[x], fb[x]);
     57     add_fib(rr, mid + 1, r, LL(fa[x]) * powa[mid + 1 - l] % MOD, LL(fb[x]) * powb[mid + 1 - l] % MOD);
     58     fa[x] = fb[x] = 0;
     59 }
     60 
     61 void build(int x, int l, int r) {
     62     if(l == r) {
     63         sum[x] = a[l];
     64     } else {
     65         build(ll, l, mid);
     66         build(rr, mid + 1, r);
     67         maintain(x);
     68     }
     69 }
     70 
     71 void update(int x, int l, int r, int a, int b) {
     72     if(a <= l && r <= b) {
     73         add_fib(x, l, r, LL(coe) * powa[l - a + 1] % MOD, LL(coe) * powb[l - a + 1] % MOD);
     74     } else {
     75         pushdown(x, l, r);
     76         if(a <= mid) update(ll, l, mid, a, b);
     77         if(mid < b) update(rr, mid + 1, r, a, b);
     78         maintain(x);
     79     }
     80 }
     81 
     82 int query(int x, int l, int r, int a, int b) {
     83     if(a <= l && r <= b) {
     84         return sum[x];
     85     } else {
     86         int ret = 0;
     87         pushdown(x, l, r);
     88         if(a <= mid) (ret += query(ll, l, mid, a, b)) %= MOD;
     89         if(mid < b) (ret += query(rr, mid + 1, r, a, b)) %= MOD;
     90         return ret;
     91     }
     92 }
     93 
     94 int main() {
     95     scanf("%d%d", &n, &m);
     96     for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
     97     init();
     98     build(1, 1, n);
     99     int op, l, r;
    100     while(m--) {
    101         scanf("%d%d%d", &op, &l, &r);
    102         if(op == 1) update(1, 1, n, l, r);
    103         if(op == 2) printf("%d
    ", query(1, 1, n, l, r));
    104     }
    105 }
    View Code
  • 相关阅读:
    使用node.js如何爬取网站数据
    关于@font-face的使用
    webpack通过postcss-loader添加浏览器前缀
    点击弹出 +1放大效果 -- jQuery插件
    网站CSS选择器性能讨论
    修改 上传图片按钮input-file样式。。
    insertAdjacentHTML方法示例
    css背景色半透明的最佳实践
    js实现选中文字 分享功能
    js实现滑动的弹性导航
  • 原文地址:https://www.cnblogs.com/oyking/p/3848682.html
Copyright © 2011-2022 走看看