Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)

/*

充分利用了菲波那切数列的两条定理:

①定义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)地计算出每一个结点中间的数是多少、每一个结点的和。

*/

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
#define maxn 300005
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll mod=1000000009;
ll fibo[maxn],sum[maxn<<2],a[maxn<<2],b[maxn<<2];
//打表菲波那切数列
void get_fibo(){
    fibo[1]=fibo[2]=1;
    for(int i=3;i<maxn;i++)
        fibo[i]=(fibo[i-1]+fibo[i-2])%mod;
}
//根据公式二得到该菲薄数列的第n个数
ll get_FB(int n,ll a1,ll b1){
    if(n==1) return a1%mod;
    else if(n==2) return b1%mod;
    else return (b1*fibo[n-1]+a1*fibo[n-2])%mod;
}
void push_up(int rt){
    sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%mod;
}
void push_down(int rt,int l,int r){
    int mid=(l+r)>>1;
    a[rt<<1]=(a[rt<<1]+a[rt])%mod;
    b[rt<<1]=(b[rt]+b[rt<<1])%mod;
    a[rt<<1|1]=(a[rt<<1|1]+get_FB(mid+1-l+1,a[rt],b[rt]))%mod;
    b[rt<<1|1]=(b[rt<<1|1]+get_FB(mid+1-l+2,a[rt],b[rt]))%mod;
    ll k1=(get_FB(mid-l+1+2,a[rt],b[rt])-b[rt]+mod)%mod;  //记录前半部分的和
    ll k2=(get_FB(r-l+1+2,a[rt],b[rt])-b[rt]-k1+mod)%mod;      //记录后半部分的和
    sum[rt<<1]=(sum[rt<<1]+k1)%mod;
    sum[rt<<1|1]=(sum[rt<<1|1]+k2)%mod;
    a[rt]=b[rt]=0;
}
void build(int l,int r,int rt){
    a[rt]=b[rt]=0;
    if(l==r){
        scanf("%d",&sum[rt]); return;
    }
    int m=(l+r)>>1;
    build(lson); build(rson);
    push_up(rt);
}
void update(ll L,ll R,ll l,ll r,ll rt){
    if(L<=l&&R>=r){
        a[rt]=(a[rt]+fibo[l-L+1])%mod;
        b[rt]=(b[rt]+fibo[l-L+2])%mod;
        sum[rt]=(sum[rt]+get_FB(r-l+1+2,fibo[l-L+1],fibo[l-L+2])-fibo[l-L+2]+mod)%mod;
        return;
    }
    push_down(rt,l,r);
    ll m=(l+r)>>1;
    if(L<=m) update(L,R,lson);
    if(R>m) update(L,R,rson);
    push_up(rt);
}
ll query(ll L,ll R,ll l,ll r,ll rt){
    if(L<=l&&R>=r) return sum[rt]%mod;
    push_down(rt,l,r);
    ll m=(l+r)>>1; ll ret=0;
    if(L<=m) ret+=query(L,R,lson);
    if(R>m) ret+=query(L,R,rson);
    return ret%mod;
}
int main(){
    ll i,j,n,m,a1,b1,c1;
    get_fibo();
    cin>>n>>m;
    build(1,n,1);
    while(m--){
        scanf("%lld%lld%lld",&a1,&b1,&c1);
        if(a1==1) update(b1,c1,1,n,1);
        else printf("%lld\n",(query(b1,c1,1,n,1)+mod)%mod);
    }
    return 0;
}
时间: 2024-10-11 04:37:03

Codeforces Round #FF (Div. 2) E. DZY Loves Fibonacci Numbers(斐波那契的定理+线段树)的相关文章

DP Codeforces Round #FF (Div. 1) A. DZY Loves Sequences

题目传送门 /* DP:先用l,r数组记录前缀后缀上升长度,最大值会在三种情况中产生: 1. a[i-1] + 1 < a[i+1],可以改a[i],那么值为l[i-1] + r[i+1] + 1 2. l[i-1] + 1 3. r[i+1] + 1 //修改a[i] */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int MAXN =

Codeforces Round #FF (Div. 1) A. DZY Loves Sequences

原题链接:http://codeforces.com/problemset/problem/446/A 题意:给一个长度为n的序列,最多可以修改一个位置的数,求最长连续上升子序列. 题解:当a[i+1] > a[i-1]+2的时候,可以通过改变a[i]的值来使前后两段合并,反之,分别考虑a[i]作为左边那段最长的和右边那段最长的. #include <cstdio> #include <cstring> #include <algorithm> #include

Codeforces Round #FF (Div. 2) A. DZY Loves Hash

DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n numbers, in the order they are given, into the hash table. For the i-th number xi, DZY will put it into the bucket numbered h(xi), where h(x) is the hash function. In

Codeforces Round #FF (Div. 2) D. DZY Loves Modification 贪心+优先队列

链接:http://codeforces.com/problemset/problem/447/D 题意:一个n*m的矩阵.能够进行k次操作,每次操作室对某一行或某一列的的数都减p,获得的得分是这一行或列原来的数字之和.求N次操作之后得到的最高得分是多少. 思路:首先分别统计每行和每列的数字和. 进行的k次操作中,有i次操作是对行进行操作,剩余k-i次操作是对列进行操作. 首先在操作中忽略每次操作中行对列的影响,然后计算列的时候,最后能够计算出,总共的影响是i*(k-i)*p. 找出对于每一个i

Codeforces Round #FF (Div. 2) C - DZY Loves Sequences (DP)

DZY has a sequence a, consisting of n integers. We'll call a sequence ai,?ai?+?1,?...,?aj (1?≤?i?≤?j?≤?n) a subsegment of the sequence a. The value (j?-?i?+?1) denotes the length of the subsegment. Your task is to find the longest subsegment of a, su

Codeforces Round #FF(255) DIV2 C - DZY Loves Sequences

A - DZY Loves Hash 水题,开辟一个数组即可 #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; int main(){ int p,n; cin >> p >> n; vector<bool> buckets(302,false); bool flag = fal

Codeforces Round #254 (Div. 2) B. DZY Loves Chemistry (并查集)

题目链接 昨天晚上没有做出来,刚看题目的时候还把题意理解错了,当时想着以什么样的顺序倒,想着就饶进去了, 也被题目下面的示例分析给误导了. 题意: 有1-n种化学药剂  总共有m对试剂能反应,按不同的次序将1-n种试剂滴入试管,如果正在滴入的试剂能与已经滴入 的试剂反应,那么危险数*2,否则维持不变.问最后最大的危险系数是多少. 分析:其实这个题根本不用考虑倒入的顺序,只是分块就行,结果就是每个子集里元素的个数-1 和  的2的幂. 1 #include <iostream> 2 #inclu

Codeforces Round #FF (Div. 1)-A,B,C

A:DZY Loves Sequences 一开始看错题了..sad. 题目很简单,做法也很简单.DP一下就好了. dp[i][0]:到当前位置,没有任何数改变,得到的长度. dp[i][1]:到当前位置,改变了一个数,得到的长度 不过需要正向求一遍,然后反向求一遍. #include<iostream> #include<stdio.h> #include<algorithm> #include<stdlib.h> #include<string.h

Codeforces Round #FF (Div. 2) 题解

比赛链接:http://codeforces.com/contest/447 A. DZY Loves Hash time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output DZY has a hash table with p buckets, numbered from 0 to p?-?1. He wants to insert n