zoukankan      html  css  js  c++  java
  • [CF446C] DZY Loves Fibonacci Numbers

    [CF446C] DZY Loves Fibonacci Numbers - 二次剩余,线段树维护等比数列

    Description

    在本题中,我们用 (f_i) 来表示第 (i) 个斐波那契数。维护一个序列 (a),长度为 (n),有 (m) 次操作:

    1. 1 l r:对于 (lle ile r),将 (a_i) 加上 (f_{i-l+1})
    2. 2 l r:求 (displaystyleleft(sum_{i=l}^ra_i ight)mod(10^9+9))

    Solution

    通项公式 (a_n=frac{1}{sqrt{5}}[(frac{sqrt{5}+1}{2})^n-(frac{sqrt{5}-1}{2})^n]),由于 (sqrt 5)(mod (10^9+9)) 下有二次剩余

    因此转化为线段树维护等比数列

    对于两个部分分别用一个线段树维护,这样公比是固定的,只需要一个 tag 表示当前节点加上的还未下传的首项即可

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    inline long long read()
    {
        long long x = 0;
        int f = 1;
        char ch = getchar();
        for (; !isdigit(ch); ch = getchar())
            if (ch == '-')
                f = -1;
        for (; isdigit(ch); ch = getchar())
            x = x * 10 + (ch ^ 48);
        return x * f;
    }
    void print(long long x)
    {
        if (x < 0)
            x = -x, putchar('-');
        if (x > 9)
            print(x / 10);
        putchar(x % 10 + '0');
    }
    
    const int mod = 1e9 + 9;
    
    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % mod, q / 2) : 1) % mod;
    }
    
    int inv(int p)
    {
        return qpow(p, mod - 2);
    }
    
    const int isq5 = 276601605;
    const int modmod = mod * mod;
    const int q1 = 691504013;
    const int q2 = 308495997;
    
    struct SegmentTree
    {
        int q; // common prop
        int invb;
        int *sum, *tag, *pw;
    
        SegmentTree(int siz)
        {
            sum = new int[siz];
            tag = new int[siz];
            pw = new int[siz];
            memset(sum, 0, sizeof sum);
            memset(tag, 0, sizeof tag);
        }
    
        void presolve(int siz)
        {
            pw[0] = 1;
            for (int i = 1; i < siz; i++)
                pw[i] = pw[i - 1] * q % mod;
            int b = 1 - q;
            b = (b + modmod) % mod;
            invb = inv(b);
        }
    
        void pushup(int p)
        {
            sum[p] = (sum[p * 2] + sum[p * 2 + 1]) % mod;
        }
    
        int qpow(int p)
        {
            return pw[p];
        }
    
        void put(int p, int l, int r, int v)
        {
            int len = r - l + 1;
            int a = 1 - qpow(len);
            a = (a + modmod) % mod;
    
            sum[p] += v % mod * a % mod * invb;
            sum[p] %= mod;
            tag[p] += v;
            tag[p] %= mod;
        }
    
        void pushdown(int p, int l, int r)
        {
            if (tag[p])
            {
                put(p * 2, l, (l + r) / 2, tag[p]);
                put(p * 2 + 1, (l + r) / 2 + 1, r, tag[p] * qpow((l + r) / 2 - l + 1) % mod);
                tag[p] = 0;
            }
        }
    
        void modify(int p, int l, int r, int ql, int qr, int first)
        {
            if (l > qr || r < ql)
                return;
            if (l >= ql && r <= qr)
            {
                int a = first * qpow(l - ql) % mod;
                put(p, l, r, a);
            }
            else
            {
                pushdown(p, l, r);
                modify(p * 2, l, (l + r) / 2, ql, qr, first);
                modify(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr, first);
                pushup(p);
            }
        }
    
        int query(int p, int l, int r, int ql, int qr)
        {
            if (l > qr || r < ql)
                return 0;
            if (l >= ql && r <= qr)
                return sum[p];
            pushdown(p, l, r);
            return (query(p * 2, l, (l + r) / 2, ql, qr) + query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr)) % mod;
        }
    };
    
    const int N = 1e6 + 5;
    
    int a[N], n, m;
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        n = read();
        m = read();
        for (int i = 1; i <= n; i++)
            a[i] = read();
        for (int i = 1; i <= n; i++)
            a[i] += a[i - 1];
    
        SegmentTree seg1(2e6), seg2(2e6);
        seg1.q = q1;
        seg2.q = q2;
        seg1.presolve(2e6);
        seg2.presolve(2e6);
    
        for (int i = 1; i <= m; i++)
        {
            int op, l, r;
            op = read();
            l = read();
            r = read();
            if (op == 1)
            {
                seg1.modify(1, 1, n, l, r, q1);
                seg2.modify(1, 1, n, l, r, q2);
            }
            else
            {
                int ans1 = seg1.query(1, 1, n, l, r);
                int ans2 = seg2.query(1, 1, n, l, r);
                int ans = (ans1 - ans2) * isq5 + a[r] - a[l - 1];
                ans %= mod;
                ans += mod;
                ans %= mod;
                print(ans);
                putchar('
    ');
            }
        }
    }
    
  • 相关阅读:
    【Office Web Apps】在 SharePoint 中使用 Office Web Apps
    css轮廓
    css定位
    css盒子模型 css3盒子相关样式
    css常用操作
    css3选择器
    强制换行和禁止换行
    text-transform 字母的大小写
    css hack
    JavaScript基本语法
  • 原文地址:https://www.cnblogs.com/mollnn/p/14642222.html
Copyright © 2011-2022 走看看