「Sasha and Array」Solution
简述题意
-
在本题中,我们用 f i f_i fi 来表示第 i i i 个斐波那契数( f 1 = f 2 = 1 , f i = f i − 1 + f i − 2 ( i ≥ 3 ) f_1=f_2=1,f_i=f_{i-1}+f_{i-2}(i\ge 3) f1=f2=1,fi=fi−1+fi−2(i≥3)。
-
给定一个 n n n 个数的序列 a a a。有 m m m 次操作,操作有两种:
- 将 a l ∼ a r a_l\sim a_r al∼ar 加上 x x x。
- 求 ( ∑ i = l r f a i ) m o d ( 1 0 9 + 7 ) \displaystyle\left(\sum_{i=l}^r f_{a_i}\right)\bmod (10^9+7) (i=l∑rfai)mod(109+7)。
-
1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1≤n,m≤105, 1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1≤ai≤109。
思路
比较简单的一道紫题。
看到斐波那契数列,而且涉及到
1
0
9
10^9
109 项甚至更多,首先想到矩阵快速幂。看到序列操作,又很自然的想到线段树。那么这道题基本上就做完了。
由于矩阵满足 a × ( b + c ) = a × b + a × c a \times (b+c)=a \times b + a \times c a×(b+c)=a×b+a×c,因此对于区间修改而言,我们只需像普通线段树一样,维护懒标记,然后下放即可。对于区间合并而言,直接将左右区间的答案累和就好了。注意这里懒标记以及和的类型都应该是 Matrix \text{Matrix} Matrix。
我们已知斐波那契的初始矩阵 A = ( 0 1 ) A=\begin{pmatrix}0 & 1\end{pmatrix} A=(01),加速矩阵为 B = ( 0 1 1 1 ) B = \begin{pmatrix} 0 & 1 \\ 1 & 1 \end{pmatrix} B=(0111),对于每次修改,我们只需要将待修改元素的累和矩阵以及懒标记矩阵乘上 B x B^x Bx 即可。
注意懒标记要初始成单位矩阵,即 B = ( 1 0 0 1 ) B = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} B=(1001)。
代码
如果上述有不理解的地方,看完代码应该就懂了。
#include<bits/stdc++.h>
#define int long long
const int MAXN = 1e5 + 5 , MOD = 1e9 + 7;
using namespace std;
int n , q , a[MAXN];
struct Matrix{ // 矩阵快速幂模板
int n , m , res[3][3];
Matrix() {memset(res , 0 , sizeof(res));}
Matrix operator * (const Matrix &b) {
Matrix tmp;
tmp.n = n , tmp.m = b.m;
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= b.m ; j ++) {
for (int k = 1 ; k <= m ; k ++) {
tmp.res[i][j] = (tmp.res[i][j] + res[i][k] * b.res[k][j] % MOD + MOD) % MOD;
}
}
}
return tmp;
}
Matrix operator ^ (int k) {
Matrix tmp , base = (*this);
tmp.n = tmp.m = m;
for (int i = 1 ; i <= m ; i ++) tmp.res[i][i] = 1;
while(k) {
if (k & 1) tmp = tmp * base;
base = base * base;
k >>= 1;
}
return tmp;
}
Matrix operator + (const Matrix &b) {
Matrix tmp;
tmp.n = n , tmp.m = m;
for (int i = 1 ; i <= n ; i ++) {
for (int j = 1 ; j <= m ; j ++) {
tmp.res[i][j] = (res[i][j] + b.res[i][j]) % MOD;
}
}
return tmp;
}
}Quick;
namespace Segment{
struct tree{
Matrix sum , add;
int l , r;
}tree[MAXN << 3];
void pushup(int p) {tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;} // 上传答案
void pushdown(int p) { // 下放懒标记(矩阵运算满足结合律)
tree[p << 1].add = tree[p << 1].add * tree[p].add , tree[p << 1 | 1].add = tree[p << 1 | 1].add * tree[p].add;
tree[p << 1].sum = tree[p << 1].sum * tree[p].add , tree[p << 1 | 1].sum = tree[p << 1 | 1].sum * tree[p].add;
tree[p].add.res[1][1] = tree[p].add.res[2][2] = 1 , tree[p].add.res[1][2] = tree[p].add.res[2][1] = 0;
}
void build(int p , int l , int r) {
tree[p].l = l , tree[p].r = r , tree[p].add.res[1][1] = tree[p].add.res[2][2] = 1; // 初始化成单位矩阵
tree[p].add.n = tree[p].add.m = 2 , tree[p].sum.n = 1 , tree[p].sum.m = 2;
if (l == r) {
tree[p].sum.res[1][1] = 0 , tree[p].sum.res[1][2] = 1;
tree[p].sum = tree[p].sum * (Quick ^ a[l]); // 求斐波那契的第 a[l] 项
return;
}
int mid = l + r >> 1;
build(p << 1 , l , mid) , build(p << 1 | 1 , mid + 1 , r);
pushup(p);
}
void update(int p , int l , int r , Matrix v) {
if (tree[p].l >= l && tree[p].r <= r) {
tree[p].add = tree[p].add * v , tree[p].sum = tree[p].sum * v;
return;
}
pushdown(p);
int mid = tree[p].l + tree[p].r >> 1;
if (l <= mid) update(p << 1 , l , r , v);
if (r > mid) update(p << 1 | 1 , l , r , v);
pushup(p);
}
int query(int p , int l , int r) {
if (tree[p].l >= l && tree[p].r <= r) {return tree[p].sum.res[1][1];}
pushdown(p);
int mid = tree[p].l + tree[p].r >> 1 , tmp = 0;
if (l <= mid) tmp = (tmp + query(p << 1 , l , r)) % MOD;
if (r > mid) tmp = (tmp + query(p << 1 | 1 , l , r)) % MOD;
return tmp;
}
}
using namespace Segment;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr) , cout.tie(nullptr);
cin >> n >> q;
Quick.n = Quick.m = 2 , Quick.res[1][2] = Quick.res[2][1] = Quick.res[2][2] = 1; // 加速矩阵
for (int i = 1 ; i <= n ; i ++) cin >> a[i];
build(1 , 1 , n);
while(q --) {
int opt , l , r , x;
cin >> opt >> l >> r;
if (opt == 1) cin >> x , update(1 , l , r , Quick ^ x);
else cout << query(1 , l , r) << '\n';
}
return 0;
}

浙公网安备 33010602011771号