[CF 446C] DZY Loves Fibonacci Numbers

题目要求维护一个数据结构,支持区间依次加斐波那契数列,区间求和。
一开始我想的是利用斐波那契数列前缀和公式,然后下传,类似于维护一个等差数列,但是很快我就发现这个思路有问题。
但是这个思路其实有用,我们考察一下斐波那契数列的通项公式:
\(f_n = \frac{1}{\sqrt{5}} [(\frac{1 + \sqrt{5}}{2})^n - (\frac{1 - \sqrt{5}}{2})^n]\)

其实斐波那契数列可以看成两个等比数列之差。本题要求取模,所以我们不妨求一下\(\sqrt{5}\)在模\(10^9+9\)意义下的模数,通过抄题解计算可以得到其模数为383008016,然后就可以愉快的维护两个等比数列了。
维护方法比较简单,显然公比一定,只需要下传首项即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<set>
#include<map>
#include<string>
#include<iostream>
#include<queue>
#include<cctype>
using namespace std;

#define A(x) cout << #x << " " << x << endl;
#define AA(x,y) cout << #x << " " << x << #y << " " << y << endl;
#define B cout << "Break" << endl;
#define ll long long
#define inf 1000000000

ll read()
{
    ll c = getchar();
    int x = 0,f = 1;
    while(!isdigit(c))
    {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(isdigit(c))
    {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return f * x;
}
#define N 300010
#define mod 1000000009
ll base1,base2,inv,n,m;
int seq[N];
ll quick_pow(ll a,ll b)
{
    ll ret = 1;
    while(b)
    {
        if(b & 1) ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret % mod;
}
struct Segment_Tree
{
    #define mid (l + r >> 1)
    #define ls x << 1,l,mid
    #define rs x << 1 | 1,mid + 1,r
    ll p[N],tree[N << 2],lazy[N << 2],q,Inv;
    void init()
    {
        p[0] = 1;
        for(ll i = 1;i <= n;++i) p[i] = p[i - 1] * q % mod;
        Inv = quick_pow(q - 1,mod - 2);
        build(1,1,n);
        return;
    }
    void push_up(ll x)
    {
        tree[x] = (tree[x << 1] + tree[x << 1 | 1]) % mod;
        return;
    }
    void build(ll x,ll l,ll r)
    {
        if(l == r) return;
        build(ls);
        build(rs);
        push_up(x);
        return;
    }
    void add(ll x,ll l,ll r,ll a)
    {
        lazy[x] += a;
        tree[x] += (a * p[r - l + 1] % mod - a + mod) % mod * Inv % mod;
        return;
    }
    void push_down(ll x,ll l,ll r)
    {
        if(!lazy[x]) return;
        add(ls,lazy[x]);
        add(rs,lazy[x] * p[r - l + 1] % mod);
        lazy[x] = 0;
    }
    void modify(ll x,ll l,ll r,ll L,ll R,ll a)
    {
        if(l == L && r == R)
        {
            add(x,l,r,a);
            return;
        }
        push_down(x,l,r);
        if(r <= mid) modify(ls,L,R,a);
        else if(l > mid) modify(rs,L,R,a);
        else
        {
            modify(ls,L,mid,a);
            modify(rs,mid + 1,R,a * p[mid - L + 1] % mod);
        }
        push_up(x);
        return;
    }
    ll query(ll x,ll l,ll r,ll L,ll R)
    {
        if(l == L && r == R) return tree[x];
        push_down(x,l,r);
        if(r <= mid) return query(ls,L,R);
        else if(l > mid) return query(rs,L,R);
        else return (query(ls,L,mid) + query(rs,mid + 1,R)) % mod;
    }

}t1,t2;

int main()
{
    t1.q = (383008016 + 1) * quick_pow(2ll,mod - 2) % mod;
    t2.q = (1 - 383008016 + mod) * quick_pow(2ll,mod - 2) % mod;
    inv = quick_pow(383008016,mod - 2);

    n = read(),m = read();
    for(ll i = 1;i <= n;++i) seq[i] = (seq[i - 1] + read()) % mod;
    t1.init(),t2.init();
    while(m--)
    {
        ll op = read(),l = read(),r = read();
        if(op == 1)
        {
            t1.modify(1,1,n,l,r,t1.q);
            t2.modify(1,1,n,l,r,t2.q);
        }
        else
        {
            ll a = t1.query(1,1,n,l,r);
            ll b = t2.query(1,1,n,l,r);
            ll ans = (a - b + mod) % mod * inv % mod;
            printf("%lld\n",((seq[r] - seq[l - 1] + mod) % mod + ans) % mod);
        }
    }

}

猜你喜欢

转载自www.cnblogs.com/lijilai-oi/p/12408152.html
今日推荐