洛谷P5678 [GZOI2017]河神 题解
题目链接:P5678 [GZOI2017]河神
题意:
cxy 从河神给的选择中,获得了一道当年挂掉的代数题的灵感。
但现在他希望你来帮忙解答,因为他自己忙着去搜妹纸资源去了。
给出数列 $\{a_n\}$ 和 $\{b_n\}$ 以及 $\{A_n\}$ 的递推关系,试求出数列 $\{A_n\}$ 第 $N$ 项。
递推关系为:
其中,$\otimes$ 表示与操作,$\oplus$ 表示或操作。
输入格式:
第一行两个正整数 $N$ 和 $K$ 。
第二行 $K$ 个空格隔开的非负整数,表示 $\{a_n\}$。
第三行 $K$ 个空格隔开的非负整数,表示 $\{b_n\}$。
输出格式:
一行,一个整数,表示$\{A_n\}$。
数据范围:
$0 \le a_i,b_i \le 2^{63} - 1,~ n \le 10^9,~ k \le 100$
考虑推广矩阵乘法使其仍满足结合律。
我们可以把 加法 变成 或运算,乘法 变成 与运算。简单证明一下:
$((AB)C)_{i,j}$ 的第 $d$ 位为 $1$ 当且仅当存在至少一对 $x,y$ 使得 $A_{i, x}, B_{x, y}, C_{y, j}$ 第 $d$ 位均为 $1$ 。
$(A(BC))_{i,j}$ 的第 $d$ 位为 $1$ 当且仅当存在至少一对 $x,y$ 使得 $A_{i, x}, B_{x, y}, C_{y, j}$ 第 $d$ 位均为 $1$ 。$\square$
则初始矩阵为:
转移矩阵:( $e$ 为单位元,取 $2^{63} - 1$ 即可 )
只要算下 $A \times M^{n - k + 1}$ 就好啦~
时间复杂度 $\mathcal{O}(k^3 \log n)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
typedef vector< vector<int> > mat;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)())
mat mul(mat A, mat B)
{
int n = A.size(), m = A[0].size(), p = B[0].size();
mat C(n, vector<int>(p));
for(int k = 0; k < m; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < p; j++)
C[i][j] |= A[i][k] & B[k][j];
return C;
}
mat qpow(mat A, int b)
{
int n = max(A.size(), A[0].size());
mat ans(n, vector<int>(n));
for(int i = 0; i < n; i++) ans[i][i] = INT64_MAX;
for(; b; b >>= 1)
{
if(b & 1) ans = mul(ans, A);
A = mul(A, A);
}
return ans;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n,K; cin >> n >> K;
mat M(K, vector<int>(K)), A(1, vector<int>(K));
for(int i = 0; i < K; i++) cin >> A[0][K - i - 1];
for(int i = 0; i < K; i++) cin >> M[K - i - 1][0];
if(n < K) return cout << A[0][n] << '\n', 0;
for(int i = 1; i < K; i++) M[i - 1][i] = INT64_MAX;
mat res = mul(A, qpow(M, n - K + 1)); cout << res[0][0] << '\n';
return 0;
}