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

洛谷P5678 [GZOI2017]河神 题解


洛谷P5678 [GZOI2017]河神 题解

题目链接:P5678 [GZOI2017]河神

题意

cxy 从河神给的选择中,获得了一道当年挂掉的代数题的灵感。

但现在他希望你来帮忙解答,因为他自己忙着去搜妹纸资源去了。

给出数列 \(\{a_n\}\)\(\{b_n\}\) 以及 \(\{A_n\}\) 的递推关系,试求出数列 \(\{A_n\}\)\(N\) 项。

递推关系为:

\[ A_n=\begin{cases}a_n & 0 \le n < K \\[8pt] \bigoplus (A_{n-K+t} \otimes b_t) & n \ge K \end{cases} \] 其中,\(\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\)

则初始矩阵为: \[ A = \left[\begin{array}{llll} a_{k} & a_{k-1} & \cdots & a_{0} \end{array}\right] \] 转移矩阵:( \(e\) 为单位元,取 \(2^{63} - 1\) 即可 ) \[ M = \left[\begin{array}{ccccc} b_1 & e &&& \\b_2 && e & \\\vdots &&& \ddots \\b_{k-1} &&&& e \\b_k &&&& \end{array}\right] \] 只要算下 \(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 !
评论
  目录