标签:des style blog http color os
In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence relation
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:
Help DZY reply to all the queries.
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.
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\n", query(1, 1, n, l, r)); 98 } 99 }
思路2:按官方题解的说法,有通项公式fib[n] = sqrt(5) / 5 * (((1 + sqrt(5)) / 2) ^ n - ((1 - sqrt(5)) / 2) ^ n)。
5是1e9+9的二次剩余,383008016^2=5(mod 1e9+9)。
利用逆元,可计算出:sqrt(5) / 5、(1 + sqrt(5)) / 2、(1 - sqrt(5)) / 2在模1e9+9意义下的值。
然后,变成用线段树维护两个等比数列。预处理出(1 + sqrt(5)) / 2和(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\n", query(1, 1, n, l, r)); 104 } 105 }
codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树),布布扣,bubuko.com
codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)
标签:des style blog http color os
原文地址:http://www.cnblogs.com/oyking/p/3848682.html