[CF718C]Sasha and Array(线段树+矩阵快速幂)
题目链接:https://codeforces.com/contest/718/problem/C
题意:给出一个序列,有两种操作,操作一:将序列中l-r部分的值加上某个数,操作二:计算Σri=lf(i) 的值第l-r项斐波那契数的和。
思路:首先我们需要解决的问题是计算第n项斐波那契数的值,n的范围的1e9,不难想到,我们可以通过使用矩阵快速幂(时间复杂度logn)来计算,其次,还有一个问题,如何进行区间修改,在我们算出第n项斐波那契数的矩阵时,我们要求在区间每个数都加上x之后的值,那么我们只需要用此区间和的矩阵乘上x的斐波那契数矩阵(这是一个结论,不难总结),大概就是假设区间和是f(2) + f(3),那么乘上x矩阵,就等于f(2) * x + f(3) * x,两者结果是相等的,而矩阵乘就等于下标相加,所以得出此结论,还要注意的是矩阵的初始值要设为单位矩阵,否则会在之后矩阵相乘运算中变成零。
AC代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cmath>
5 #include<cstring>
6 #define int long long
7 #define ll long long
8 using namespace std;
9 //const int N = 100010;
10 const int mod = 1e9 + 7;
11 const int N = 2;
12 const int Maxn = 1e5 + 10;
13
14 int n = 2;
15
16 struct Matrix {
17
18 int x[N][N];
19 void init() {
20 x[0][0] = x[1][0] = x[0][1] = 1;
21 x[1][1] = 0;
22 }
23 void unit() {
24 memset(x, 0, sizeof(x));
25 for (int i = 0; i < N; i++) {
26 x[i][i] = 1;
27 }
28 }
29 int flag = 1;
30 void clear() {
31 memset(x, 0, sizeof(x));
32 flag = 0;
33 }
34 bool empty() {
35 if (!x[0][0] && !x[0][1] && !x[1][0] && !x[1][1]) return true;
36 else return false;
37 }
38
39 };
40 Matrix operator * (const Matrix& m1,const Matrix& m2) {
41
42 Matrix ans;
43 for (int i = 0; i < n; i++) {
44 for (int j = 0; j < n; j++) {
45 int tmp = 0;
46 for (int k = 0; k < n; k++) {
47 tmp = (tmp + (m1.x[i][k] * m2.x[k][j]) % mod) % mod;
48 }
49 ans.x[i][j] = tmp;
50 }
51 }
52
53 return ans;
54 }
55 Matrix operator + (const Matrix& m1, const Matrix& m2) {
56
57 Matrix ans;
58 for (int i = 0; i < n; i++) {
59 for (int j = 0; j < n; j++) {
60 ans.x[i][j] = (m1.x[i][j] + m2.x[i][j]) % mod;
61 }
62 }
63
64 return ans;
65 }
66
67 Matrix Quick_MatPow(Matrix m, int p) {
68
69 Matrix ans;
70 ans.unit();
71 Matrix base = m;
72 while (p) {
73 if (p & 1) {
74 ans = ans * base;
75 }
76 base = base * base;
77 p >>= 1;
78 }
79
80 return ans;
81 }
82
83 Matrix a;
84
85 int A[Maxn];
86 Matrix Sum[Maxn << 2], lazy[Maxn << 2];
87
88 //int fib[N << 2];
89 //
90 //ll tmp[2][2], res[2][2];
91 //
92 //void multi(ll a[][2], ll b[][2], int n)
93 //{
94 // memset(tmp, 0, sizeof(tmp));
95 // for (ll i = 0; i < n; i++)
96 // {
97 // for (ll j = 0; j < n; j++)
98 // {
99 // for (ll k = 0; k < n; k++)
100 // {
101 // tmp[i][j] += (a[i][k] * b[k][j]) % mod;
102 // }
103 // tmp[i][j] = tmp[i][j] % mod;
104 // }
105 // }
106 // for (ll i = 0; i < n; i++)
107 // for (ll j = 0; j < n; j++)
108 // a[i][j] = tmp[i][j];
109 //}
110 //
111 //void Pow(ll a[][2], ll m, int n)
112 //{
113 // memset(res, 0, sizeof(res));//m是幂,n是矩阵大小
114 // for (ll i = 0; i < n; i++) res[i][i] = 1;
115 // while (m)
116 // {
117 // if (m & 1)
118 // multi(res, a, n);//res=res*a;复制直接在multi里面实现了;
119 // multi(a, a, n);//a=a*a
120 // m >>= 1;
121 // }
122 //}
123
124 void PushUp(int rt) {
125 Sum[rt] = Sum[rt << 1] + Sum[rt << 1 | 1];
126 //FibSum[rt] = FibSum[rt << 1] + FibSum[rt << 1 | 1];
127 }
128
129 void Build(int l, int r, int rt) {
130 //lazy[rt].unit();
131 if (l == r) {
132 //Sum[rt] = A[l];
133 Sum[rt] = Quick_MatPow(a, A[l]);
134 //cout << Sum[rt].x[1][0] << " ";
135 return;
136 }
137 int m = (l + r) >> 1;
138 Build(l, m, rt << 1);
139 Build(m + 1, r, rt << 1 | 1);
140 PushUp(rt);
141 }
142
143 //void PointUpdate(int L, int C, int l, int r, int rt) {
144 // if (l == r) {
145 // //Sum[rt] = C;
146 // return;
147 // }
148 // int m = (l + r) >> 1;
149 // if (L <= m) PointUpdate(L, C, l, m, rt << 1);
150 // else PointUpdate(L, C, m + 1, r, rt << 1 | 1);
151 // PushUp(rt);
152 //}
153
154 void PushDown(int rt, int ln, int rn) {
155 if (!lazy[rt].empty()) {
156 if (lazy[rt << 1].empty()) lazy[rt << 1] = lazy[rt];
157 else lazy[rt << 1] = lazy[rt << 1] * lazy[rt];
158 if(lazy[rt << 1 | 1].empty()) lazy[rt << 1 | 1] = lazy[rt];
159 else lazy[rt << 1 | 1] = lazy[rt << 1 | 1] * lazy[rt];
160 Sum[rt << 1] = Sum[rt << 1] * lazy[rt];
161 Sum[rt << 1 | 1] = Sum[rt << 1 | 1] * lazy[rt];
162 lazy[rt].clear();
163 }
164 }
165
166 void QjUpdate(int L, int R, Matrix C, int l, int r, int rt) {
167 if (l >= L && r <= R) {
168 Sum[rt] = Sum[rt] * C;
169 //cout << "---------" << Sum[rt].x[1][0] << "\n";
170 if (lazy[rt].empty()) lazy[rt] = C;
171 else lazy[rt] = lazy[rt] * C;
172 return;
173 }
174 int m = (l + r) >> 1;
175 PushDown(rt, m - l + 1, r - m);
176 if (m >= L) QjUpdate(L, R, C, l, m, rt << 1);
177 if (m < R) QjUpdate(L, R, C, m + 1, r, rt << 1 | 1);
178 PushUp(rt);
179 }
180
181 Matrix Query(int L, int R, int l, int r, int rt) {
182 if (l >= L && r <= R) {
183 return Sum[rt];
184 }
185 int m = (l + r) >> 1;
186 PushDown(rt, m - l + 1, r - m);
187 Matrix ANS;
188 ANS.clear();
189 if (m >= L) ANS = ANS + Query(L, R, l, m, rt << 1);
190 if (m < R) ANS = ANS + Query(L, R, m + 1, r, rt << 1 | 1);
191 return ANS;
192 }
193
194 void print(int l, int r, int rt) {
195 if (l == r) {
196 cout << Sum[rt].x[1][0] << " ";
197 return;
198 }
199 int m = (l + r) >> 1;
200 PushDown(rt, m - l + 1, r - m);
201 print(l, m, rt << 1);
202 print(m + 1, r, rt << 1 | 1);
203 PushUp(rt);
204 }
205
206 signed main() {
207
208 ios::sync_with_stdio(false);
209 cin.tie(0);
210 int t, q;
211 //cin >> n;
212 a.init();
213 cin >> t >> q;
214 /*for (int i = 1; i <= 100; i++) {
215 cout << Quick_MatPow(a, i).x[1][0] << "\n";
216 }*/
217 for (int i = 1; i <= t; i++) {
218 cin >> A[i];
219 }
220 Build(1, t, 1);
221 //cout << "\n";
222 while (q--) {
223 int op;
224 cin >> op;
225 if (op == 1) {
226 int x, y, w;
227 cin >> x >> y >> w;
228 Matrix h = Quick_MatPow(a, w);
229 //cout << h.x[1][0] << "----\n";
230 QjUpdate(x, y, h, 1, t, 1);
231 //print(1, t, 1);
232 cout << "\n";
233 }
234 else {
235 int x, y;
236 cin >> x >> y;
237 cout << Query(x, y, 1, t, 1).x[1][0] << "\n";
238 }
239 }
240
241 return 0;
242 }
永远热爱,永远向着光。