【Codeforces Round #FF (Div. 2)】E. DZY Loves Fibonacci Numbers
2015-10-12 10:11
369 查看
题目
E. DZY Loves Fibonacci Numbers
BackgroundIn 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 m queries, 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.
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.
Sample test(s) input
4 4
1 2 3 4
1 1 4
2 1 4
1 2 4
2 1 3
output
17
12
Note
After the first query, a = [2, 3, 5, 7].
For the second query, sum = 2 + 3 + 5 + 7 = 17.
After the third query, a = [2, 4, 6, 9].
For the fourth query, sum = 2 + 4 + 6 = 12.
思路
这是一个显然的区间修改与查询问题,想到使用线段树但是每一个区间修改的值不一样,怎么办呢TAT
F1=F2=1的Fibonacci数列有以下性质
Fn=Fn−2+Fn−1
F1+F2+…+Fn=Fn+2−1
而且两个Fibonacci数列逐项相加仍然示意个Fibonacci数列
将上述的两个性质推广到H1=a H2=b的Fibonacci数列,得到以下性质
Hn=a∗Fn−2+b∗Fn−1
H1+H2+…+Hn=Hn+2−b
这样就解决了区间修改问题,对于每一个区间记tag就改为维护一个长度固定的Fibonacci数列,对每一个区间记录这个数列的前两项,当pushdown时也可以O(1)地修改子区间的前两项
代码
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a); i <= (b); i++) #define red(i, a, b) for(int i = (a); i >= (b); i--) #define ll long long const int N = 333333; const ll mod = 1000000009ll; int n, m; struct node { int l, r; ll sum, f1, f2; }t[N * 6]; ll a , F ; inline ll read() { ll x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) { x = x * 10ll + c - '0'; c = getchar(); } return x; } void calc_Fibonacci(int n) { F[1] = 1; F[2] = 1; rep(i, 3, N) F[i] = (F[i - 1] + F[i - 2]) % mod; } ll calc(ll a, ll b, ll n) { if (n == 1) return a; else if (n == 2) return b; else return (a * F[n - 2] % mod + b * F[n - 1] % mod) % mod; } ll calc_range(ll a, ll b, ll n) { if (n == 1) return a; else if (n == 2) return (a + b) % mod; else return (calc(a, b, n + 2) - b + mod) % mod; } void build(int x, int l, int r) { int mid = (l + r) / 2, lc = x * 2, rc = x * 2 + 1; t[x].l = l; t[x].r = r; if (l == r) { t[x].sum = a[l]; t[x].f1 = t[x].f2 = 0; return; } build(lc, l, mid); build(rc, mid + 1, r); t[x].sum = (t[lc].sum + t[rc].sum) % mod; t[x].f1 = t[x].f2 = 0; } void pushdown(int x) { int l = t[x].l, r = t[x].r; int mid = (l + r) / 2, lc = x * 2, rc = x * 2 + 1; t[lc].f1 = (t[lc].f1 + t[x].f1) % mod; t[lc].f2 = (t[lc].f2 + t[x].f2) % mod; t[lc].sum += calc_range(t[x].f1, t[x].f2, mid - l + 1); t[lc].sum %= mod; t[rc].f1 = (t[rc].f1 + calc(t[x].f1, t[x].f2, mid - l + 2)) % mod; t[rc].f2 = (t[rc].f2 + calc(t[x].f1, t[x].f2, mid - l + 3)) % mod; t[rc].sum += calc_range(t[x].f1, t[x].f2, r - l + 1) - calc_range(t[x].f1, t[x].f2, mid - l + 1); t[rc].sum = (t[rc].sum + mod) % mod; t[x].f1 = t[x].f2 = 0; } void update(int x, int l, int r, int ql, int qr) { int mid = (l + r) / 2, lc = x * 2, rc = x * 2 + 1; if (l >= ql && r <= qr) { t[x].f1 = (t[x].f1 + F[l - ql + 1]) % mod; t[x].f2 = (t[x].f2 + F[l - ql + 2]) % mod; t[x].sum += calc_range(F[l - ql + 1], F[l - ql + 2], r - l + 1); t[x].sum %= mod; return; } pushdown(x); if (ql <= mid) update(lc, l, mid, ql, qr); if (qr > mid) update(rc, mid + 1, r, ql, qr); t[x].sum = (t[lc].sum + t[rc].sum) % mod; return; } ll query(int x, int l, int r, int ql, int qr) { int mid = (l + r) / 2, lc = x * 2, rc = x * 2 + 1; if (l >= ql && r <= qr) return t[x].sum; pushdown(x); ll ans_left = 0, ans_right = 0; if (ql <= mid) ans_left = query(lc, l, mid, ql, qr); if (qr > mid) ans_right = query(rc, mid + 1, r, ql, qr); return (ans_left + ans_right) % mod; } int main() { n = read(); m = read(); calc_Fibonacci(n); rep(i, 1, n) a[i] = read(); build(1, 1, n); rep(i, 1, m) { int tag, l, r; tag = read(); l = read(); r = read(); if (tag == 1) update(1, 1, n, l, r); else printf("%lld\n", query(1, 1, n, l, r)); } return 0; }
尾声
我的运行时间成功跑到了Accepted中的倒数第三不过代码长度倒是排在第一面的
调试时间之长源自于把%mod写成%n,也是醉
这次的思路和公式写的很好看
终于知道Markdown怎么调字体了
SR真是Hentai呢
End.
相关文章推荐
- Java 大型系统高并发大数据的处理方式
- 高项 10月10日作业
- 常变量和符号变量的区别
- 【bzoj1226】
- php 两个文件之间的相对路径的计算方法
- 旧版Xcode下载地址
- ps修图之——四步去修图后的毛边
- SRM 670 DIV 2 Cdgame 250-point
- 求第n个数的值
- 17.1.1.9 Introducing Additional Slaves to an Existing Replication Environment
- Centos 6.5 DNS配置
- 低版本visual studio如何打开用高版本visual studio编写的工程
- oracle 11g RAC 常用命令
- java常用工具类(不定时更新)
- CSS3新增UI样式
- [swift] NSClassFromString 无法获得该类
- hihocoder1241 : Best Route in a Grid
- pat1038Recover the Smallest Number (30)
- 黑马程序员——构造函数,构造代码块,静态代码块的区别
- Hibernate hql 查询指定字段并获取结果集