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:
- Format of the query "1 l r". In reply to the query, you need to add Fi - l + 1 to each element ai, where l ≤ i ≤ r.
- Format of the query "2 l r". In reply to the query you should output the value of
modulo 1000000009 (109 + 9).
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):
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
#define ll (x << 1)
#define rr ((x << 1) | 1)
#define mid ((l + r) >> 1) const int MOD = 1e9 + ; const int MAXN = ;
const int MAXT = MAXN << ; int f1[MAXT], f2[MAXT], sum[MAXT];
int a[MAXN], fib[MAXN];
int n, m; void init() {
fib[] = fib[] = ;
for(int i = ; i <= n + ; ++i) {
fib[i] = fib[i - ] + fib[i - ];
if(fib[i] >= MOD) fib[i] -= MOD;
}
} int get_fib(int a, int b, int n) {
if(n == ) return a;
if(n == ) return b;
return (LL(b) * fib[n - ] + LL(a) * fib[n - ]) % MOD;
} int get_sum(int a, int b, int n) {
return (get_fib(a, b, n + ) - b + MOD) % MOD;
} void add_fib(int x, int l, int r, int a, int b) {
(f1[x] += a) %= MOD;
(f2[x] += b) %= MOD;
(sum[x] += get_sum(a, b, r - l + )) %= MOD;
} void pushdown(int x, int l, int r) {
add_fib(ll, l, mid, f1[x], f2[x]);
add_fib(rr, mid + , r, get_fib(f1[x], f2[x], mid + - l + ), get_fib(f1[x], f2[x], mid + - l + ));
f1[x] = f2[x] = ;
} void maintain(int x) {
sum[x] = (sum[ll] + sum[rr]) % MOD;
} void build(int x, int l, int r) {
if(l == r) {
sum[x] = a[l];
} else {
build(ll, l, mid);
build(rr, mid + , r);
maintain(x);
}
} void update(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
add_fib(x, l, r, fib[l - a + ], fib[l + - a + ]);
} else {
pushdown(x, l, r);
if(a <= mid) update(ll, l, mid, a, b);
if(mid < b) update(rr, mid + , r, a, b);
maintain(x);
}
} int query(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
return sum[x];
} else {
int ret = ;
pushdown(x, l, r);
if(a <= mid) (ret += query(ll, l, mid, a, b)) %= MOD;
if(mid < b) (ret += query(rr, mid + , r, a, b)) %= MOD;
return ret;
}
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i) scanf("%d", &a[i]);
init();
build(, , n);
int op, l, r;
while(m--) {
scanf("%d%d%d", &op, &l, &r);
if(op == ) update(, , n, l, r);
if(op == ) printf("%d\n", query(, , n, l, r));
}
}
思路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):
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
#define ll (x << 1)
#define rr ((x << 1) | 1)
#define mid ((l + r) >> 1) const int MOD = 1e9 + ;
const int SQRT5 = ; const int MAXN = ;
const int MAXT = MAXN << ; int powa[MAXN], powb[MAXN];
int coe, ta, tb, invta, invtb;
int fa[MAXT], fb[MAXT], sum[MAXT];
int a[MAXN];
int n, m; int inv(int x) {
if(x == ) return ;
return (LL(MOD - MOD / x) * inv(MOD % x)) % MOD;
} void init() {
coe = inv(SQRT5);
ta = (LL( + SQRT5) * inv()) % MOD;
tb = (LL( - SQRT5 + MOD) * inv()) % MOD;
invta = inv( - ta + MOD);
invtb = inv( - tb + MOD);
//cout<<coe<<endl<<ta<<endl<<tb<<endl;
powa[] = powb[] = ;
for(int i = ; i <= n; ++i) {
powa[i] = LL(powa[i - ]) * ta % MOD;
powb[i] = LL(powb[i - ]) * tb % MOD;
}
} void maintain(int x) {
sum[x] = (sum[ll] + sum[rr]) % MOD;
} void add_fib(int x, int l, int r, int a, int b) {
(fa[x] += a) %= MOD;
(fb[x] += b) %= MOD;
(sum[x] += LL(a) * ( - powa[r - l + ] + MOD) % MOD * invta % MOD) %= MOD;
(sum[x] -= LL(b) * ( - powb[r - l + ] + MOD) % MOD * invtb % MOD) %= MOD;
if(sum[x] < ) sum[x] += MOD;
} void pushdown(int x, int l, int r) {
add_fib(ll, l, mid, fa[x], fb[x]);
add_fib(rr, mid + , r, LL(fa[x]) * powa[mid + - l] % MOD, LL(fb[x]) * powb[mid + - l] % MOD);
fa[x] = fb[x] = ;
} void build(int x, int l, int r) {
if(l == r) {
sum[x] = a[l];
} else {
build(ll, l, mid);
build(rr, mid + , r);
maintain(x);
}
} void update(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
add_fib(x, l, r, LL(coe) * powa[l - a + ] % MOD, LL(coe) * powb[l - a + ] % MOD);
} else {
pushdown(x, l, r);
if(a <= mid) update(ll, l, mid, a, b);
if(mid < b) update(rr, mid + , r, a, b);
maintain(x);
}
} int query(int x, int l, int r, int a, int b) {
if(a <= l && r <= b) {
return sum[x];
} else {
int ret = ;
pushdown(x, l, r);
if(a <= mid) (ret += query(ll, l, mid, a, b)) %= MOD;
if(mid < b) (ret += query(rr, mid + , r, a, b)) %= MOD;
return ret;
}
} int main() {
scanf("%d%d", &n, &m);
for(int i = ; i <= n; ++i) scanf("%d", &a[i]);
init();
build(, , n);
int op, l, r;
while(m--) {
scanf("%d%d%d", &op, &l, &r);
if(op == ) update(, , n, l, r);
if(op == ) printf("%d\n", query(, , n, l, r));
}
}
codeforces 446C DZY Loves Fibonacci Numbers(数学 or 数论+线段树)(两种方法)的更多相关文章
- Codeforces 446-C DZY Loves Fibonacci Numbers 同余 线段树 斐波那契数列
C. DZY Loves Fibonacci Numbers time limit per test 4 seconds memory limit per test 256 megabytes inp ...
- ACM学习历程—Codeforces 446C DZY Loves Fibonacci Numbers(线段树 && 数论)
Description In mathematical terms, the sequence Fn of Fibonacci numbers is defined by the recurrence ...
- codeforces 446C DZY Loves Fibonacci Numbers 数论+线段树成段更新
DZY Loves Fibonacci Numbers Time Limit:4000MS Memory Limit:262144KB 64bit IO Format:%I64d &a ...
- Codeforces 446C —— DZY Loves Fibonacci Numbers(线段树)
题目:DZY Loves Fibonacci Numbers 题意比較简单,不解释了. 尽管官方的题解也是用线段树,但还利用了二次剩余. 可是我没有想到二次剩余,然后写了个感觉非常复杂度的线段树,还是 ...
- Codeforces 446C DZY Loves Fibonacci Numbers [线段树,数论]
洛谷 Codeforces 思路 这题知道结论就是水题,不知道就是神仙题-- 斐波那契数有这样一个性质:\(f_{n+m}=f_{n+1}f_m+f_{n}f_{m-1}\). 至于怎么证明嘛-- 即 ...
- Codeforces 446C - DZY Loves Fibonacci Numbers(斐波那契数列+线段树)
Codeforces 题目传送门 & 洛谷题目传送门 你可能会疑惑我为什么要写 *2400 的题的题解 首先一个很明显的想法是,看到斐波那契数列和 \(10^9+9\) 就想到通项公式,\(F ...
- codeforces 446C DZY Loves Fibonacci Numbers 线段树
假如F[1] = a, F[2] = B, F[n] = F[n - 1] + F[n - 2]. 写成矩阵表示形式可以很快发现F[n] = f[n - 1] * b + f[n - 2] * a. ...
- Codeforces Round #FF 446 C. DZY Loves Fibonacci Numbers
參考:http://www.cnblogs.com/chanme/p/3843859.html 然后我看到在别人的AC的方法里还有这么一种神方法,他预先设定了一个阈值K,当当前的更新操作数j<K ...
- [CodeForces - 447E] E - DZY Loves Fibonacci Numbers
E DZY Loves Fibonacci Numbers In mathematical terms, the sequence Fn of Fibonacci numbers is define ...
随机推荐
- [daily][CentOS][yum] 删除包的同时一同清理掉安装时一起装进来的依赖包
说起来有点绕口,这个需求是这样的. 就是我yum装A包的时候,同时安装了A的依赖包a1,a2,a3. 当我们使用yum remove A卸载A包的是,a1,a2,a3包并不会一同被卸载掉.如果他们没有 ...
- [dpdk] 读官方文档(1)
前提:已读了这本书<<深入浅出dpdk(朱清河等著)>>. 目标:读官方文档,同时跟着文档进行安装编译等工作. http://dpdk.org/doc/guides/index ...
- mysql 数据库封装类:返回索引、关联、字符串数组;分页查询封装类 :$page=new Page(表的总条数,每页的条数);$sql = "".$page->limit; echo $page->fpage();
<?php class czy { public $host="localhost"; //地址 public $uid="root"; //用户名 pu ...
- JavaScript判断字符串的字符长度(中文占两个字符)
判断方法 //判断字符串中的字符 中文算两个字符 function chkstrlen(str) { ; ; i < str.length; i++) { ) //如果是汉字,则字符串长度加2 ...
- 在Asp.net MVC中访问静态页面
有时候由于一些特殊的需要,我们需要在MVC中访问HTML页面,假如您将这个页面放在Views中的话,去访问将会收到一个404,但是放在Views外面的目录则不受此限制. 那么我们就来解决View里面的 ...
- [转]ANDROID L——Material Design详解(动画篇)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! 转自:http://blog.csdn.net/a396901990/article/de ...
- Eclipse代码风格
1.代码对齐风格:project...properties...Java Code Style...Formatter...Brance
- C语言课本实例
1. 将一维数组的内容倒顺 #include <stdio.h>void func(int *s,int n){ int i,temp; for(i=0;i<n/2;i++) { t ...
- UVA 10127题目的解答
#include <iostream>#include <cstdio>#include <cmath> int main(){ int num; while (s ...
- MySQL学习笔记——复制的实现原理
1.三个线程 MYSQL复制是从主服务器复制到一个或多个从服务器的异步过程,在主服务器与从服务器之间实现整个复制过程主要由三个线程来实现,其中一个线程I\O在主服务器器端,另两个线程(SQL线程和I\ ...