Codeforces 575A. Fibonotci
题目大意
- 给出一个递推式:
F
n
=
s
n
−
1
∗
F
n
−
1
+
s
n
−
2
∗
F
n
−
2
F_n=s_{n-1}*F_{n-1}+s_{n-2}*F_{n-2}
Fn=sn−1∗Fn−1+sn−2∗Fn−2,
- 且
F
0
=
0
F_0=0
F0=0,
F
1
=
1
F_1=1
F1=1.
-
s
s
s的值有周期性,除特殊限制外
s
i
=
s
i
m
o
d
N
s_i=s_{imod N}
si=simodN,
- 特殊限制有
m
m
m组,每组的形式为将
s
j
s_j
sj改为
v
v
v,其中
j
≥
N
j≥N
j≥N(即特殊情况不会第一段循环节内),
- 求
F
k
m
o
d
P
F_kmod P
FkmodP.
-
N
,
M
≤
5
∗
1
0
4
N,M≤5*10^4
N,M≤5∗104
-
P
,
s
i
,
v
≤
1
0
9
P,s_i,v≤10^9
P,si,v≤109
-
k
,
j
≤
1
0
18
k,j≤10^{18}
k,j≤1018
题解
- 如果没有特殊限制,看到
k
k
k那么大,直接就会想到矩阵乘法,
- 由于每一位的系数不一样,可以先用倍增求出不同位下(
<
N
<N
<N)向右
2
i
2^i
2i步的转移矩阵(
2
∗
2
2*2
2∗2),然后直接倍增做即可。
- 但是有特殊限制的话,该怎么办呢?
- 其实方法也是类似的,只是矩乘不是一次做到底,而是每次碰到一个限制就停下来,然后对于特殊限制,直接往后计算两位,因为被修改的值在计算
s
n
+
1
s_{n+1}
sn+1和
s
n
+
2
s_{n+2}
sn+2时都需要,
- 当然会有一些要注意的地方,比如出现连续的限制,那么中间一次矩乘都不能做,而是要把一连串的限制都计算完后,再继续做矩乘。
- 预处理复杂度
O
(
N
log
2
k
)
O(Nlog_2k)
O(Nlog2k),矩乘总复杂度
O
(
N
log
2
k
)
O(Nlog_2k)
O(Nlog2k)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 50010
ll a[N], f[N][62][2][2];
struct node {
ll x, s;
}c[N];
int cmp(node x, node y) {
return x.x < y.x;
}
int main() {
ll K, P, i, j;
int n, m;
scanf("%lld%lld", &K, &P);
scanf("%d", &n);
for(i = 0; i < n; i++) scanf("%lld", &a[i]);
scanf("%d", &m);
for(i = 1; i <= m; i++) scanf("%lld%lld", &c[i].x, &c[i].s);
m++;
c[m].x = K + 1, c[m].s = 0;
sort(c + 1, c + m + 1, cmp);
for(i = 0; i < n; i++) {
f[i][0][0][0] = 0;
f[i][0][1][0] = 1;
f[i][0][0][1] = a[(i - 1 + n) % n];;
f[i][0][1][1] = a[i];
}
for(j = 1; j < 62; j++) {
for(i = 0; i < n; i++) {
ll k = (i + (1ll << (j - 1))) % n;
f[i][j][0][0] = (f[i][j - 1][0][1] * f[k][j - 1][1][0] + f[i][j - 1][0][0] * f[k][j - 1][0][0]) % P;
f[i][j][0][1] = (f[i][j - 1][0][1] * f[k][j - 1][1][1] + f[i][j - 1][0][0] * f[k][j - 1][0][1]) % P;
f[i][j][1][0] = (f[i][j - 1][1][1] * f[k][j - 1][1][0] + f[i][j - 1][1][0] * f[k][j - 1][0][0]) % P;
f[i][j][1][1] = (f[i][j - 1][1][1] * f[k][j - 1][1][1] + f[i][j - 1][1][0] * f[k][j - 1][0][1]) % P;
}
}
ll la = 1;
ll s0 = 0, s1 = 1;
for(i = 1; i <= m; i++) {
ll t = c[i].x, p = t - la, x = la;
ll g[2][2], h[2][2];
g[0][0] = g[1][1] = 1, g[0][1] = g[1][0] = 0;
for(j = 61; j >= 0; j--) if(p >= (1ll << j)) {
p -= 1ll << j;
h[0][0] = (g[0][1] * f[x % n][j][1][0] + g[0][0] * f[x % n][j][0][0]) % P;
h[0][1] = (g[0][1] * f[x % n][j][1][1] + g[0][0] * f[x % n][j][0][1]) % P;
h[1][0] = (g[1][1] * f[x % n][j][1][0] + g[1][0] * f[x % n][j][0][0]) % P;
h[1][1] = (g[1][1] * f[x % n][j][1][1] + g[1][0] * f[x % n][j][0][1]) % P;
g[0][0] = h[0][0], g[1][0] = h[1][0], g[0][1] = h[0][1], g[1][1] = h[1][1];
x += 1ll << j;
}
ll t0 = (s0 * g[0][0] + s1 * g[1][0]) % P, t1 = (s0 * g[0][1] + s1 * g[1][1]) % P;
if(t == K + 1) {
printf("%lld
", t0 % P);
break;
}
s1 = (t0 * a[(t - 1 + n) % n] + t1 * c[i].s) % P;
s0 = t1 % P;
la = t + 1;
while(c[i + 1].x == c[i].x + 1) {
ll s2 = (s0 * c[i].s + s1 * c[i + 1].s) % P;
s0 = s1, s1 = s2;
la++;
if(la == K) {
printf("%lld
", s1);
return 0;
}
i++;
}
ll s2 = (s0 * c[i].s + s1 * a[la % n]) % P;
s0 = s1, s1 = s2;
la++;
if(la == K) {
printf("%lld
", s1);
break;
}
}
return 0;
}