在本题中,我们用 \(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)\)。
线段树满足所有条件!!!
线段树上每个点都搞成一个矩阵即可。
具体请看代码。
#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; }