分块打表 H. The Nth Item @ The 2019 Asia Nanchang First Round Online Programming Contest
题意
1e7次询问f(n)%998244353: n<1e18
f
(
0
)
=
0
,
f
(
1
)
=
1
;
f
(
i
)
=
3
f
(
i
−
1
)
+
2
f
(
i
−
2
)
f(0)=0,f(1)=1;\\ f(i)=3f(i-1)+2f(i-2)\\
f(0)=0,f(1)=1;f(i)=3f(i−1)+2f(i−2)
题解
题目要求O(1)地求二阶线性递推数列的第n项。矩阵快速幂可以
O
(
4
l
o
g
n
)
O(4logn)
O(4logn)求,其中4为矩阵乘法常数。当然也可以选择求解递推式,得到:
f
(
n
)
=
(
(
(
3
+
17
)
2
)
n
−
(
(
3
−
17
)
2
)
n
)
/
17
f(n)=((\frac{(3+\sqrt {17})}{2})^n-(\frac{(3-\sqrt {17})}{2})^n)/\sqrt{17}
f(n)=((2(3+17))n−(2(3−17))n)/17
利用二次剩余得到
17
M
O
D
998244353
\sqrt {17}MOD998244353
17MOD998244353,快速幂的复杂度为
O
(
2
l
o
g
n
)
O(2logn)
O(2logn)。
问题是如何降到O(1)?
首先尝试找循环节,如果循环节<1e7即可预处理出所有取值,然而循环节为$ 499122176$ 无法直接预处理。
考虑矩阵转移式:
(
f
(
n
+
1
)
f
(
n
)
)
=
(
3
2
1
0
)
n
⋅
(
1
0
)
\begin{pmatrix} f(n+1) \\ f(n) \end{pmatrix} =\begin{pmatrix} 3 & 2\\ 1 & 0 \end{pmatrix}^n \cdot \begin{pmatrix} 1 \\ 0 \end{pmatrix}
(f(n+1)f(n))=(3120)n⋅(10)
令
T
=
(
3
2
1
0
)
T=\begin{pmatrix} 3 & 2\\ 1 & 0 \end{pmatrix}
T=(3120)
于是原问题等价于O(1)查询
T
n
T^n
Tn。
考虑分块,每隔i个数算一次T并存下来,有:
T
i
,
T
2
i
,
T
3
i
.
.
.
T^i,T^{2i},T^{3i}...
Ti,T2i,T3i...
对于某次查询
T
n
T^n
Tn,必定落在
[
T
⌊
n
i
⌋
i
,
T
⌊
n
i
⌋
i
+
i
)
[T^{\lfloor \frac{n}{i}\rfloor i},T^{\lfloor \frac{n}{i}\rfloor i+i})
[T⌊in⌋i,T⌊in⌋i+i)
为了求
T
n
T^n
Tn还需乘上
T
n
%
i
T^{\ n\%i}
T n%i
这部分我们可以暴力算,当然也可以再打一个表存
T
1
,
T
2
.
.
.
T
i
−
1
T^1,T^2...T^{i-1}
T1,T2...Ti−1
打表预处理的时空复杂度为
T
(
n
)
=
n
/
i
+
i
T(n)=n/i+i
T(n)=n/i+i
i
=
n
i=\sqrt n
i=n 时取到最小值
O
(
2
n
)
O(2\sqrt n)
O(2n),当然这道题利用循环节,i 取100即可,600ms过。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<iostream>
#define ll long long
using namespace std;
const int N = 2;
const int inf = 50010;
typedef long long LL;
const int MOD = 998244353;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
struct Matrix
{
LL m[N][N];
};
Matrix A;
Matrix I = { 1, 0, 0, 1 };
Matrix multi(Matrix a, Matrix b)
{
Matrix c;
for (int i = 0; i<N; i++)
{
for (int j = 0; j<N; j++)
{
c.m[i][j] = 0;
for (int k = 0; k<N; k++)
{
c.m[i][j] += a.m[i][k] * b.m[k][j];
c.m[i][j] %= MOD;
}
}
}
return c;
}
Matrix power(Matrix A, LL n)
{
Matrix ans = I, p = A;
while (n)
{
if (n & 1)
{
ans = multi(ans, p);
n--;
}
n >>= 1;
p = multi(p, p);
}
return ans;
}
int L = 499122176;
Matrix as[101];
const int maxn = 5e6;
Matrix tab[maxn + 1];
ll f(int x) {
Matrix ans = multi(tab[x/100],as[x%100]);
return ans.m[1][0] ;
}
int main()
{
as[0]={ 1, 0, 0, 1 };
as[1].m[0][0] = 3;
as[1].m[0][1] = 2;
as[1].m[1][0] = 1;
as[1].m[1][1] = 0;
rep(i, 1, 99) {
as[i + 1] = multi(as[i] ,as[1]);
}
tab[0] = { 1, 0, 0, 1 };
rep(i, 1, maxn) {
tab[i] = multi(tab[i - 1], as[100]);
}
ll q, n;
cin >> q >> n;
ll ans = 0;
ll now = 0, last = n;
rep(i, 1, q) {
now = f((last-1)%L+1);
ans ^= now;
last = (now*now)^last;
}
cout << ans << endl;
cin >> n;
return 0;
}
/*
1 1
499122176
*/