zoukankan      html  css  js  c++  java
  • cf447E DZY Loves Fibonacci Numbers

    传送门
    这题是真的牛

    • 区间加操作,使得区间的值加上对应的斐波那契数列。
    • 区间查询操作,求区间和

    其实这有个规律,看见斐波那契数列和(mod)(1e9 + 9),就知道要用二次剩余来搞了,因为斐波那契的通项公式(sqrt{5})在模(1e9 + 9)下是有二次剩余的。

    根据二次剩余,斐波那契的另一个表达式为

    [F_n equiv 276601605(691504013^n-308495997^n) space (modspace 1e9+9) ]

    那么就可以把这题转换为用线段树维护一下等比数列了。但是注意的是,这题是有两个等比数列,因为等比数列加等比数列不一定是等比数列,除非(q)相同。
    那么维护两个等比数列,线段树里构建两个值用于维护当前的左区间的首项值,两个区间的公比是不同的。

    注意的时,在每次修改都需要注意首项的值,因为操作里面首项(a_1)是对于给出的左区间而言的,所以对于每个线段区间,都需要处理好当前左区间的首项值。而且,在pushdown时也需要注意变化右孩子的首项值。

    考虑到在线段树里面用快速幂会乘上一个(logn)的时间复杂度,所以就先预处理下两个公比的幂次方,等比数列求和时分母的逆元的值。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define ll long long
    using namespace std;
    const int N = 3e5 + 5;
    const int mod = 1e9 + 9;
    const int q1 = 691504013, q2 = 308495997;
    const int aa1 = 138300803, aa2 = 861699207;
    const int inv1 = 691504013, inv2 = 308495997;
    ll mul1[N] = {1}, mul2[N] = {1};
    void ex_gcd(ll a, ll b, ll &d, ll &x, ll &y){
        if(!b) {
            d = a, x = 1, y = 0;
            return;
        }
        ex_gcd(b, a % b, d, y, x);
        y -= x * (a / b);
    }
    ll inv(ll a, ll p){//求a在p模下的逆元
        ll d, x, y;
        ex_gcd(a, p, d, x, y);
        return d == 1 ? (x % p + p) % p : -1;//d = 1时才有逆元
    }
    ll S(ll n, ll a1, ll q){
        if(q == q1) return (a1 * (mul1[n] - 1) % mod * inv1 % mod + mod) % mod;
        return (a1 * (mul2[n] - 1) % mod * inv2 % mod + mod) % mod;
    }
    struct SegTree{
        struct Node{
            int l, r;
            ll sum, a1, a2;
            #define l(p) tree[p].l
            #define r(p) tree[p].r
            #define sum(p) tree[p].sum
            #define a1(p) tree[p].a1
            #define a2(p) tree[p].a2
            #define lson (p << 1)
            #define rson (p << 1 | 1)
        } tree[N << 2];
        void pushup(int p){
            sum(p) = (sum(lson) + sum(rson) + mod) % mod;
        }
        void pushdown(int p) {
            if(a1(p)) {
                a1(lson) += a1(p); a1(lson) = (a1(lson) % mod + mod) % mod;
                a1(rson) += mul1[l(rson) - l(lson)] * a1(p) % mod; a1(rson) = (a1(rson) % mod + mod) % mod;
                sum(lson) += S(r(lson) - l(lson) + 1, a1(p), q1); sum(lson) = (sum(lson) % mod + mod) % mod;
                sum(rson) += S(r(rson) - l(rson) + 1, mul1[l(rson) - l(lson)] * a1(p) % mod, q1); sum(rson) = (sum(rson) % mod + mod) % mod;
                a1(p) = 0;
            }
            if(a2(p)) {
                a2(lson) += a2(p); a2(lson) = (a2(lson) % mod + mod) % mod;
                a2(rson) += mul2[l(rson) - l(lson)] * a2(p) % mod; a2(rson) = (a2(rson) % mod + mod) % mod;
                sum(lson) += S(r(lson) - l(lson) + 1, a2(p), q2); sum(lson) = (sum(lson) % mod + mod) % mod;
                sum(rson) += S(r(rson) - l(rson) + 1, mul2[l(rson) - l(lson)] * a2(p) % mod, q2); sum(rson) = (sum(rson) % mod + mod) % mod;
                a2(p) = 0;
            }
        }
        void build(int p, int l, int r){
            l(p) = l, r(p) = r;
            a1(p) = a2(p) = sum(p) = 0;
            if(l == r) return;
            int mid = (l + r) >> 1;
            build(lson, l, mid); build(rson, mid + 1, r);
            pushup(p);
        }
        void Change(int p, int l, int r, int c){//[l,r]
            if(l <= l(p) && r(p) <= r){
                if(c == q1) {
                    ll shou = 1ll * aa1 * mul1[l(p) - l] % mod; shou = (shou + mod) % mod;
                    a1(p) += shou, a1(p) = (a1(p) + mod) % mod; 
                    sum(p) += S(r(p) - l(p) + 1, shou, q1), sum(p) = (sum(p) % mod + mod) % mod;
                } 
                if(c == q2) {
                    ll shou = 1ll * aa2 * mul2[l(p) - l] % mod; shou = (shou + mod) % mod;
                    a2(p) += shou, a1(p) = (a1(p) + mod) % mod; 
                    sum(p) += S(r(p) - l(p) + 1, shou, q2), sum(p) = (sum(p) % mod + mod) % mod;
                }
                return;
            }
            pushdown(p);
            int mid = (l(p) + r(p)) >> 1;
            if(l <= mid) Change(lson, l, r, c);
            if(r > mid) Change(rson, l, r, c);
            pushup(p);
        }
        ll Query(int p, int l, int r) { // [l,r]区间查询
            if(l <= l(p) && r(p) <= r) {
                return (sum(p) % mod + mod) % mod;
            }
            pushdown(p);
            int mid = (l(p) + r(p)) >> 1;
            ll ans = 0;
            if(l <= mid) ans += Query(lson, l, r), ans = (ans % mod + mod) % mod;
            if(r > mid) ans += Query(rson, l, r), ans = (ans % mod + mod) % mod;
            return ans = (ans % mod + mod) % mod;;
        }
    } seg;
    namespace IO {
        template <typename T>
        inline void w(T x) { if (x > 9) w(x / 10); putchar(x % 10 + 48); }
        template <typename T>
        inline void write(T x, char c) { if(x < 0) putchar('-'), x = -x; w(x); putchar(c); }
        template <typename T>
        inline void read(T &x) {
            x = 0; T f = 1; char c = getchar();
            for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
            for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
            x *= f;
        }
    };
    int n, m;
    int a[N];
    void subtask1(int l, int r){
        seg.Change(1, l, r, q1);
        seg.Change(1, l, r, q2);
    }
    void subtask2(int l, int r){
        ll ans = a[r] - a[l - 1];
        ans += seg.Query(1, l, r); ans = (ans % mod + mod) % mod;
        IO::write(ans, '
    ');
    }
    int main(){
        for(int i = 1; i <= N - 3; i++) {
            mul1[i] = 1ll * mul1[i - 1] * q1 % mod;
            mul2[i] = 1ll * mul2[i - 1] * q2 % mod;
        }
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++) IO::read(a[i]), a[i] = (a[i] + a[i - 1]) % mod;
        seg.build(1, 1, n);
        for(int i = 1; i <= m; i++) {
            int op, l, r;
            IO::read(op), IO::read(l), IO::read(r);
            if(op == 1) subtask1(l, r);
            else subtask2(l, r);
        }
        return 0;
    }
    
  • 相关阅读:
    7.12.2
    7.12.1
    7.11.8
    循环测试条件前缀和后缀的区别
    7.11.7 两个版本
    7.11.5
    7.12 vowels.c 程序
    7.11 animals.c 程序
    7.6.2 break 语句
    7.10 break.c 程序
  • 原文地址:https://www.cnblogs.com/Emcikem/p/14226493.html
Copyright © 2011-2022 走看看