题解 P5678 【[GZOI2017]河神】
CherryPockyOvO · · 题解
本题是对 矩阵概念理解 的考察
前置讲解
我们先来看一下矩阵的定义式
\sum_{k = 1}^m A_{i, k} \times B_{k, j}
然后我们发现根据题意 发现这道题目实质上是
将 求和 变成 或 |
将 乘法 变成 与 &
故只要将矩阵乘法的板子的运算符号改一下就阔以了。 即
\bigoplus_{k = 1}^m A_{i, k} \otimes B_{k, j}
解题思路
得到上面柿子之后我们对转移矩阵进行构造,因为每次转移需要用到 k 个值
所以状态矩阵大小 1
模拟题意
易构造出矩阵
状态矩阵
转移矩阵
其中 INF & a (a <
INF 取 (1 << 63) - 1 就行了
下面就是正常的矩阵快速幂的过程,这里不再赘述。
code
#include<bits/stdc++.h>
#define debug(x) cerr << #x << " = " << x <<endl;
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define INF ((1ull << 63) - 1)
using namespace std;
template<typename Tp> void Cmax(Tp &x, Tp y) { x = max(x, y); }
template<typename Tp> void Csum(Tp &x, Tp y) { x = x + y; }
template<typename Tp>
void read(Tp &x){
x = 0; int f = 1;
char ch = getchar();
while(!isdigit(ch)){ if(ch == '-') f = -1; ch = getchar(); }
while(isdigit(ch)){ x = x * 10 + ch - 48; ch = getchar(); }
x = x * f;
}
typedef unsigned long long ULL;
typedef double doub;
const int N = 130;
int n, k;
ULL f[N], C[N][N];
void mul(){
ULL ff[N];
memset(ff, 0, sizeof ff);
rep(i, 0, k - 1)
rep(j, 0, k - 1)
ff[i] |= f[j] & C[j][i]; // 实质上改的 只有这里
memcpy(f, ff, sizeof f);
}
void mulself(){
ULL ff[N][N];
memset(ff, 0, sizeof ff);
rep(i, 0, k - 1)
rep(j, 0, k - 1)
rep(t, 0, k - 1)
ff[i][j] |= C[i][t] & C[t][j]; // 改的只 有这里
memcpy(C, ff, sizeof C);
}
signed main(){
read(n); read(k);
for(int i = k - 1; i >= 0; --i)
read(f[i]);
for(int i = k - 1; i >= 0; --i)
read(C[i][0]);
rep(i, 0, k - 1)
C[i][i + 1] = INF;
if(k >= n){
printf("%llu\n", f[k - n]);
return 0;
}
n = n - k + 1;
while(n){
if(n & 1)
mul();
n >>= 1;
mulself();
}
printf("%llu\n", f[0]);
return 0;
}