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 ...
随机推荐
- pro5
1.本次课学到的知识点 (1)循环结构的概念 在我们需要重复进行某个步骤是就需要运用到循环结构. (2)三种循环语句 for,while,do-while是三种常用的循环语句,其中while的适用范围 ...
- css背景图片定位练习(二): background-position的百分比
background-position:x y; 百分比定位并不能直观的看出来,需要通过计算. background-position百分比计算公式: (容器宽度—背景图片的宽度)*x%=xpx(容器 ...
- SWT常用组件(转)
转载自:http://www.cnblogs.com/happyPawpaw/archive/2012/10/19/2730478.html 1按钮组件(Button) (1)Button组件常用样式 ...
- Tram---poj1847(简单最短路)
题目链接:http://poj.org/problem?id=1847 题意:给了N个交叉口,每个交叉口有自己能转到的交叉口. 注意这里:First number in the i-th line, ...
- BetterZip,支持rar等多种压缩解压方式(Xcode自身不能解压rar)
百度云盘下载链接: http://pan.baidu.com/s/1sk7Faw9密码: muw7 rarosx-5.3.0.tar.gz1.解压之后放到/usr/local/目录下(位置可选,不过要 ...
- UILabel 添加图片
//设置显示图片 NSMutableAttributedString * cellAttributeStr = [[NSMutableAttributedString alloc]initWithSt ...
- Java学习-040-级联删除目录中的文件、目录
之前在写应用模块,进行单元测试编码的时候,居然脑洞大开居然创建了一个 N 层的目录,到后来删除测试结果目录的时候,才发现删除不了了,提示目录过长无法删除.网上找了一些方法,也找了一些粉碎机,都没能达到 ...
- Selenium2学习-029-WebUI自动化实战实例-027-判断元素是否存在
非常简单的源码,敬请各位小主参阅.若有不足之处,敬请大神指正,不胜感激! /** * Verify the element exist or not * * @author Aaron.ffp * @ ...
- Java学习-003-JDK、JRE、JVM简介
此文主要对 JDK.JRE.JVM进行简单的介绍,给各位亲们一个参考.若有不足之处,敬请各位大神指正,不胜感激! 一.基本概念 JDK(Java Development Kit:Java 开发工具包) ...
- Java Difference between Private and Protected
Private means this could only be seen within this class. Protected means "package private" ...