欢迎使用CSDN-markdown编辑器
来源:互联网 发布:哈登16 17赛季数据 编辑:程序博客网 时间:2024/05/20 08:02
原题目
E. DZY Loves Fibonacci Numbers
time limit per test4 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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 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.
Examples
input
4 4
1 2 3 4
1 1 4
2 1 4
1 2 4
2 1 3
output
17
12
因为数据只有3e5,然后我就用分块写了,但是还有一个比较快的线段树的写法。
分块:因为两个斐波那契数列的和依然符合斐波那契的规律,所以对于某一块,只需要保存所有更新它的斐波那契的前两个值就可以了,那么可以根据这两个值,推出后面所有位要加的值,还要维护某一块里所有元素的和,这个只需要预处理1e5范围内的斐波那契的前缀和就可以了。
#include<bits/stdc++.h>using namespace std; const int N = 3e5+100; const int B = 555; const long long MOD= 1e9+9; struct node{ int x,y; };node b[555];int sum[N];int su[B];int n,q;int F[N];int sF[N];inline int read(){ int k=0; char f=1; char c=getchar(); for(;!isdigit(c);c=getchar() ) if(c=='-') f=-1; for(;isdigit(c);c=getchar() ) k=k*10+c-'0'; return k*f;}void add(int &x,int y){ x += y; if(x >= MOD) x -= MOD;}int sub(int x,int y){ x -= y; if(x < 0) x += MOD; return x;}void init(){ F[1]= 1; F[2] = 1; sF[1] = 1; sF[2] = 2; for(int i= 3;i < N;i ++){ F[i] = (F[i-1]+F[i-2])%MOD; add(sF[i],F[i]); add(sF[i],sF[i-1]); }}void update(int l,int r){ int lb = l/B,rb = r/B; if(lb == rb){ for(int i= l;i <= r;i ++){ add(sum[i],F[i-l+1]); add(su[lb],F[i-l+1]); } return ; } else{ for(int i = l;i < lb*B+B;i ++){ add(sum[i],F[i-l+1]); add(su[lb],F[i-l+1]); } for(int i= rb*B;i <= r;i ++){ add(sum[i],F[i-l+1]); add(su[rb],F[i-l+1]); } for(int i = lb+1;i < rb;i ++){ int sta = i*B; add(b[i].x,F[sta-l+1-1]); add(b[i].y,F[sta-l+1]); add(su[i],sub(sF[sta-l+B],sF[sta-l])); } }}int query(int l,int r){ int lb = l/B,rb = r/B; if(lb == rb){ int ans = 0; int bef1 = b[lb].x,bef2 = b[lb].y; for(int i = lb*B;i < l;i ++){ swap(bef1,bef2); add(bef2,bef1); } for(int i = l;i <= r;i ++){ add(ans,bef2); add(ans,sum[i]); swap(bef1,bef2); add(bef2,bef1); } return ans; } else{ int ans = 0; int bef1 = b[lb].x,bef2 = b[lb].y; for(int i = lb*B;i < l;i ++){ swap(bef1,bef2); add(bef2,bef1); } for(int i = l;i < lb*B+B;i ++){ add(ans,bef2); add(ans,sum[i]); swap(bef1,bef2); add(bef2,bef1); } //cout <<"!!!" << ans <<endl; for(int i= lb+1;i < rb;i ++){ add(ans,su[i]); } //cout <<"!!!" << ans <<endl; bef1 = b[rb].x,bef2 = b[rb].y; for(int i= rb*B;i <= r;i ++){ add(ans,bef2); add(ans,sum[i]); swap(bef1,bef2); add(bef2,bef1); } //cout <<"!!!" << ans <<endl; return ans; }}int main(){ init(); scanf("%d %d",&n,&q); for(int i = 1;i <= n;i ++) { //scanf("%d",&sum[i]); sum[i] = read(); add(su[i/B],sum[i]); } for(int i= 1;i <= q;i ++){ int op,l,r; op = read(); l = read(); r = read(); if(op == 1){ update(l,r); } else { printf("%d\n",query(l,r)); } //cout <<b[1].x << ' '<<b[1].y << endl; } return 0;}
线段树:这里要讲一个性质,如果知道某个数组符合斐波那契性质,和这个数组的前两个数,那么可以o(1)求出来这个数列的第x位的值,方法是,预处理斐波那契数列每一位包含多少个f(1)和f(2),然后乘一下就好了,然后对于线段树,每个节点记录以这加到一段的数列的前两项,对于左儿子,直接把数值加到左儿子上面就好了,对于右儿子用上面的方法求出再加到右儿子上。
对比两个方法,明显分块比较好写,但是时间复杂度略高,博主线段树还没写,,,以后补。
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 欢迎使用CSDN-markdown编辑器
- 【HDU 2577】How to Type
- PHP 中如何正确统计中文字数
- ORACLE日期时间函数大全
- (约瑟夫环公式)Joseph
- JSP的第2代开发技术:JSP+EJB
- 欢迎使用CSDN-markdown编辑器
- ios蓝牙开发(三)app作为外设被连接的实现
- 知生涯—职业顾问—怎样平衡工作与家庭?
- Linux的GRUB简介
- unix时间戳转成date-oracle
- 搬砖中的小事之代码(七)---设置数据库中非空字段的默认值
- linux脚本实现ssh自动登陆远程桌面
- 生成二维码
- ngrok使用教程--反向代理