嘘~ 正在从服务器偷取页面 . . .

洛谷P5678 [GZOI2017]河神 题解


洛谷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;
}

文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录