CF718C Sasha and Array

题目大意

在本题中,我们用 \(f_i\) 来表示第 \(i\) 个斐波那契数 \(f_1=f_2=1,f_i=f_{i-1}+f_{i-2}(i\ge 3)\)。

给定一个 \(n\) 个数的序列 \(a\)。

有 \(m\) 次操作,操作有两种:

  • 将 \(a_l\sim a_r\) 加上 \(x\)。

  • 求 \(\displaystyle\left(\sum_{i=l}^r f_{a_i}\right)\bmod (10^9+7)\)。

\(1\le n,m\le 10^5\),\(1\le a_i\le 10^9\)。

解题思路

两个操作,区间加,区间求和。

显然线段树。

斐波那契数怎么搞?

\(\mathcal O(n)\) 预处理显然爆。

显然用 \(\mathcal O(\log n)\) 的矩阵快速幂来求。

设 \(base=\begin{pmatrix}1&1\\1&0\end{pmatrix}\),则有 \(\begin{bmatrix} f_n && f_{n-1} \\ f_{n-1} && f_{n-2}\end{bmatrix}=\begin{pmatrix}1&0\\0&1\end{pmatrix} * base^{n-1}\)。

由于矩阵具有分配律,即 \(a\times b+a\times c=a\times(b+c)\),所以对于一段区间的矩阵可以相加维护,所以 \(\sum\limits_{i=l}^{r}f(a_i+x)=f_x*\sum\limits_{i=l}^{r}(a_i)\)。

线段树满足所有条件!!!

线段树上每个点都搞成一个矩阵即可。

具体请看代码。

CODE

#include <bits/stdc++.h>

#define int long long

inline int read()
{
    int s = 0, f = 0;
    char ch = getchar();
    while (!isdigit(ch))
        f |= (ch == '-'), ch = getchar();
    while (isdigit(ch))
        s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
    return f ? -s : s;
}

using namespace std;

const int _ = 1e5 + 5;

const int INF = 1e9 + 7;

const int mod = 1e9 + 7;

struct Matrix
{
    int a[3][3];
    Matrix() { memset(a, false, sizeof a); }
    void Init() { a[1][1] = a[2][2] = 1, a[1][2] = a[2][1] = 0; }
    bool pd() { return a[1][1] == 1 && a[2][2] == 1 && a[1][2] == 0 && a[2][1] == 0; }
    Matrix operator+(const Matrix b)
    {
        Matrix res;
        for (int i = 1; i <= 2; ++i)
            for (int j = 1; j <= 2; ++j)
                res.a[i][j] = (a[i][j] + b.a[i][j]) % mod;
        return res;
    }
    Matrix operator*(const Matrix b)
    {
        Matrix res;
        for (int k = 1; k <= 2; ++k)
            for (int i = 1; i <= 2; ++i)
                for (int j = 1; j <= 2; ++j)
                    res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]) % mod;
        return res;
    }
    Matrix operator^(int b)
    {
        Matrix res, Base;
        for (int i = 1; i <= 2; ++i)
            res.a[i][i] = 1;
        for (int i = 1; i <= 2; ++i)
            for (int j = 1; j <= 2; ++j)
                Base.a[i][j] = a[i][j];
        while (b)
        {
            if (b & 1)
                res = res * Base;
            Base = Base * Base;
            b >>= 1;
        }
        return res;
    }
} base, ans;

int n, m, a[_];

namespace Seg_tree
{
#define lson i << 1
#define rson i << 1 | 1
    struct Tree
    {
        Matrix sum, lazy;
    } tree[_ << 2];
    void Push_up(int i) { tree[i].sum = tree[lson].sum + tree[rson].sum; }
    void Build(int i, int l, int r)
    {
        tree[i].lazy.Init();
        if (l == r)
        {
            if (a[l] == 1)
                tree[i].sum.a[1][1] = 1;
            else if (a[l] == 2)
                tree[i].sum.a[1][1] = tree[i].sum.a[1][2] = 1;
            else
                tree[i].sum = ans * (base ^ (a[l] - 2));
            return;
        }
        int mid = (l + r) >> 1;
        Build(lson, l, mid), Build(rson, mid + 1, r);
        Push_up(i);
    }
    void Push_down(int i)
    {
        if (tree[i].lazy.pd())
            return;
        tree[lson].lazy = tree[lson].lazy * tree[i].lazy;
        tree[rson].lazy = tree[rson].lazy * tree[i].lazy;
        tree[lson].sum = tree[lson].sum * tree[i].lazy;
        tree[rson].sum = tree[rson].sum * tree[i].lazy;
        tree[i].lazy.Init();
    }
    void Modify(int i, int l, int r, int L, int R, Matrix k)
    {
        if (L <= l && r <= R)
        {
            tree[i].lazy = tree[i].lazy * k, tree[i].sum = tree[i].sum * k;
            return;
        }
        Push_down(i);
        int mid = (l + r) >> 1;
        if (mid >= L)
            Modify(lson, l, mid, L, R, k);
        if (mid < R)
            Modify(rson, mid + 1, r, L, R, k);
        Push_up(i);
    }
    int Query(int i, int l, int r, int L, int R)
    {
        if (L <= l && r <= R)
            return tree[i].sum.a[1][1];
        Push_down(i);
        int mid = (l + r) >> 1, ans = 0;
        if (mid >= L)
            ans = (ans + Query(lson, l, mid, L, R)) % mod;
        if (mid < R)
            ans = (ans + Query(rson, mid + 1, r, L, R)) % mod;
        return ans;
    }
}

signed main()
{
    base.a[1][1] = base.a[1][2] = base.a[2][1] = 1;
    ans.a[1][1] = ans.a[1][2] = 1;
    n = read(), m = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    Seg_tree::Build(1, 1, n);
    for (int i = 1, opt, l, r, k; i <= m; ++i)
    {
        opt = read(), l = read(), r = read();
        if (opt == 1)
        {
            k = read();
            Seg_tree::Modify(1, 1, n, l, r, base ^ k);
        }
        else
        {
            printf("%lld\n", Seg_tree::Query(1, 1, n, l, r));
        }
    }
    return 0;
}
上一篇:043.数组-一维数组案例-五只小猪称体重


下一篇:【Matlab 043期】【数学建模】基于多种预测模型进行公路流量预测matlab