题解 P5678 【[GZOI2017]河神】
NaCly_Fish · · 题解
为了方便,我们记序列
考虑用矩阵快速幂来解决,此处我们更改矩阵乘法的定义:将原本的乘法改为按位与,原本的加法改为按位或。
那么就能得到:
这里的
然后直接做就行了。
(水题解的屑)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<bitset>
#define N 100003
#define reg register
#define ull unsigned long long
#define inf 0xffffffffffffffffull
using namespace std;
inline void read(int &x){
x = 0;
char c = getchar();
while(c<'0'||c>'9') c = getchar();
while(c>='0'&&c<='9'){
x = (x<<3)+(x<<1)+(c^48);
c = getchar();
}
}
struct matrix{
ull a[101][101];
int siz;
inline matrix(int siz=0):siz(siz){ memset(a,0,sizeof(a)); }
inline matrix operator * (const matrix& b) const{
matrix res = matrix(siz);
for(reg int i=0;i!=siz;++i)
for(reg int j=0;j!=siz;++j)
for(reg int k=0;k!=siz;++k)
res.a[i][j] |= a[i][k]&b.a[k][j];
return res;
}
};
inline matrix power(matrix a,int t){
matrix res = matrix(a.siz);
for(reg int i=0;i!=a.siz;++i) res.a[i][i] = inf;
while(t){
if(t&1) res = res*a;
a = a*a;
t >>= 1;
}
return res;
}
int n,k;
ull a[N],f[103];
matrix A;
int main(){
ull ans = 0;
scanf("%d%d",&n,&k);
for(reg int i=0;i<k;++i) scanf("%llu",&a[i]);
for(reg int i=1;i<=k;++i) scanf("%llu",&f[i]);
if(n<=k){
printf("%llu",a[n]);
return 0;
}
reverse(f+1,f+k+1);
for(reg int i=0;i!=k;++i) A.a[i][0] = f[i+1];
for(reg int i=1;i!=k;++i) A.a[i-1][i] = inf;
A.siz = k;
A = power(A,n-k+1);
for(reg int i=0;i<k;++i)
ans |= a[k-i-1]&A.a[i][0];
printf("%llu",ans);
return 0;
}