题目链接
题目概括
给定一个无限长循环序列\(s\),从\(0\)开始标号,开始给定从零开始的循环节\({s_0,s_1\cdots s_{n-1}}\)。
然后修改其中的\(m\)项为\(v_i\)。
定义\(f_i=s_{i-1}\times f_{i-1}+s{i-2}\times f_{i-2}\)。
求\(f_k\)。(答案对\(P\)取模)
数据范围 \(n,m\leq 5\times 10^4;s_i,P,p_i\leq 10^{18};v_i\leq 10^9\)
思路要点
用线段树维护循环节。
斐波那契数列用矩阵乘法维护。
对于修改的部分暴力处理。
时间复杂度\(\mathcal O(m\times (log_2 n))\)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5;
int MOD, n, m;
long long k;
int s[N];
void add(int& x, int y) {
x += y;
if (x >= MOD) {
x -= MOD;
}
}
struct Matrix {
int a[2][2];
Matrix() { }
Matrix(int x) {
a[0][0] = x;
a[0][1] = 0;
a[1][0] = 0;
a[1][1] = x;
}
Matrix(int A, int B, int C, int D) {
a[0][0] = A;
a[0][1] = B;
a[1][0] = C;
a[1][1] = D;
}
Matrix operator * (Matrix b) {
Matrix c(0);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
for (int k = 0; k < 2; k++) {
add(c.a[i][j], (long long)a[i][k] * b.a[k][j] % MOD);
}
}
}
return c;
}
};
ostream& operator << (ostream& out, Matrix a) {
out << " [ ";
for (int i = 0; i < 2; i++) {
if (i != 0) {
out << " ";
}
for (int j = 0; j < 2; j++) {
out << a.a[i][j] << ' ';
}
out << "\n]"[i == 1];
}
return out;
}
struct Mdy {
long long pos;
int v;
bool operator < (Mdy b) const {
return pos < b.pos;
}
};
Mdy mdy[N];
Matrix operator ^ (Matrix x, long long y) {
Matrix res(1);
for (; y; y >>= 1, x = x * x) {
if (y & 1) {
res = res * x;
}
}
return res;
}
namespace segmentTree {
Matrix tr[N << 2];
void build(int x, int l, int r) {
if (l == r) {
tr[x] = Matrix(s[(l - 1 + n) % n], 1, s[(l - 2 + n) % n], 0);
return;
}
int mid = (l + r) >> 1;
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1, r);
tr[x] = tr[x << 1] * tr[x << 1 | 1];
}
Matrix query(int x, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
return tr[x];
}
int mid = (l + r) >> 1;
Matrix res(1);
if (ql <= mid) {
res = res * query(x << 1, l, mid, ql, qr);
}
if (qr > mid) {
res = res * query(x << 1 | 1, mid + 1, r, ql, qr);
}
return res;
}
}
// namespace segmentTree
using namespace segmentTree;
Matrix get(long long l, long long r) {
if (l > r) {
return Matrix(1);
}
if (l / n == r / n) {
return query(1, 0, n - 1, l % n, r % n);
}
return query(1, 0, n - 1, l % n, n - 1) * (tr[1] ^ (r / n - l / n - 1)) * query(1, 0, n - 1, 0, r % n);
}
int main() {
scanf("%lld %d %d", &k, &MOD, &n);
if (k <= 1) {
printf("%lld\n", k % MOD);
return 0;
}
for (int i = 0; i < n; i++) {
scanf("%d", &s[i]);
s[i] %= MOD;
}
build(1, 0, n - 1);
scanf("%d", &m);
for (int i = 1; i <= m; i++) {
scanf("%lld %d", &mdy[i].pos, &mdy[i].v);
mdy[i].v %= MOD;
}
sort(mdy + 1, mdy + m + 1);
while (mdy[m].pos >= k) {
m--;
}
// for (int i = 1; i <= m; i++) {
// cerr << "debug1 : " << mdy[i].pos << ' ' << mdy[i].v << '\n';
// }
Matrix res(1);
for (int i = 1; i <= m; i++) {
res = res * get(i == 1 ? 2 : mdy[i - 1].pos + 3, mdy[i].pos);
int j = i;
while (j < m && mdy[j + 1].pos - 1 == mdy[j].pos) {
j++;
}
res = res * Matrix(mdy[i].v, 1, s[(mdy[i].pos - 1) % n], 0);
for (int k = i + 1; k <= j; k++) {
res = res * Matrix(mdy[k].v, 1, mdy[k - 1].v, 0);
}
res = res * Matrix(s[(mdy[j].pos + 1) % n], 1, mdy[j].v, 0);
i = j;
}
res = res * get(m ? mdy[m].pos + 3 : 2, k + 1);
// cerr << res << '\n';
printf("%d\n", res.a[0][1]);
return 0;
}