题解 P5678
Solution
给定了递推式,要快速求递推式的值,显然想到矩阵快速幂
我们将矩阵快速幂中原本的加法定义为"|"运算(即按位或),将乘法定义为"&"运算(即按位与),根据题意,写出转移式:
其中
转移矩阵
根据题意,初始矩阵为
同样为方便起见,
所以最终答案就是
注意题目中
还有就是当
时间复杂度
Code
#include <bits/stdc++.h>
#define N (int) 105
#define ll long long
using namespace std;
ll input () {
ll x = 0, f = 0;
char c = getchar ();
while (c < '0' || c > '9') f = c == '-', c = getchar ();
while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar ();
return f ? - x : x;
}
const ll maxx = (1ull<<63)-1;
int n, k;
ll a[N], b[N];
struct Matrix { // 矩阵
int n, m;
ll a[N][N];
friend Matrix operator * (const Matrix & x, const Matrix & y) { // 定义矩阵乘法
Matrix ret;
ret.n = x.n, ret.m = y.m;
for (int i = 1; i <= x.n; i ++) {
for (int j = 1; j <= y.m; j ++) {
for (int k = 1; k <= x.m; k ++) {
ret.a[i][j] |= x.a[i][k] & y.a[k][j];
}
}
}
return ret;
}
Matrix () {
n = m = 0;
memset (a, 0, sizeof (a));
}
} mat0, mat1;
Matrix ksm (Matrix x, int y) { // 矩阵快速幂
Matrix ret = x;
y --;
while (y) {
if (y & 1) ret = ret * x;
x = x * x;
y >>= 1;
}
return ret;
}
int main () {
n = input (), k = input ();
for (int i = 1; i <= k; i ++) a[i] = input ();
for (int i = 1; i <= k; i ++) b[i] = input ();
if (n <= k) { // 特判
printf ("%lld\n", a[n]);
return 0;
}
mat1.n = mat1.m = k; // 转移矩阵
for (int i = 1; i <= k; i ++)
mat1.a[i][1] = b[k-i+1];
for (int i = 1; i < k; i ++)
mat1.a[i][i+1] = maxx;
mat0.n = 1, mat0.m = k; // 初始矩阵
for (int i = 1; i <= k; i ++)
mat0.a[1][i] = a[k-i+1];
Matrix ans = mat0 * ksm (mat1, n-k+1);
printf ("%lld\n", ans.a[1][1]);
return 0;
}
Conclusion
1 加速递推式——矩阵快速幂
2 注意一些细节(如下标从