题解:P5678 [GZOI2017] 河神

题目传送门

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

递推关系为。

\[A_n=\begin{cases}a_n & 0 \le n < K \\ \bigoplus (A_{n-K+t} \otimes b_t) & n \ge K \end{cases} \]

其中,\(\otimes\) 表示与操作,\(\oplus\) 表示或操作。

容易得到,\(A_n\) 只与 \(b_i\)\(A_i\) 的前 \(k\) 项有关。所以我们可以构建一下矩阵(假设 \(k=4\))。

\[\begin{bmatrix}A_i&A_{i+1}&A_{i+2}&A_{i+3}\end{bmatrix}\times\begin{bmatrix}0&0&0&b_1\\-1&0&0&b_2\\0&-1&0&b_3\\0&0&-1&b_4\end{bmatrix}=\begin{bmatrix}A_{i+1}&A_{i+2}&A_{i+3}&A_{i+4}\end{bmatrix} \]

在这个矩阵里,我们要把原先的结果矩阵第 \(i\)\(j\)\(=\) 第一个矩阵的第 \(i\)\(\times\) 第二个矩阵的第 \(j\) 列再相加,把 \(\times\) 改为按位与,把相加改为按位或就可以了。

那么最终的答案如下(以 \(k=4\) 为例)。

\[\begin{bmatrix}a_1&a_2&a_3&a_4\end{bmatrix}\times\begin{bmatrix}0&0&0&b_1\\-1&0&0&b_2\\0&-1&0&b_3\\0&0&-1&b_4\end{bmatrix}^{n-4}=\begin{bmatrix}A_{n-3}&A_{n-2}&A_{n-1}&A_{n}\end{bmatrix} \]

所以代码也就很好打了,这里解释一下为什么第二的矩阵里面是 \(-1\) 而不是 \(1\),这是因为是要进行与运算,而一个数与上 \(-1\) 还等于他自己,所以用 \(-1\)。而 \(0\) 是因为任何数或 \(0\) 等于他自己。

代码。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=101,N=1010101;
const int mod=1e4;
ll n,m,s,t,k,num,w[N],T,a[N],b[N];
struct tt{
	ll a[M][M];
	tt(){memset(a,0,sizeof(a));}
	tt operator*(const tt &b)const{
		tt res;
		for(int i=1;i<=k;i++)
			for(int j=1;j<=k;j++)
				for(int l=1;l<=k;l++)
					res.a[i][j]=(res.a[i][j]|(a[i][l]&b.a[l][j]));
		return res;
	}
}ans,base,st;
void qpow(tt base,ll y){
	while(y){
		if(y&1)ans=ans*base;
		base=base*base;
		y>>=1;
	}
}
int main(){
	scanf("%lld%lld",&n,&k);
	n++;
	for(int i=1;i<=k;i++)scanf("%lld",&a[i]),ans.a[1][i]=a[i];
	for(int i=1;i<=k;i++)scanf("%lld",&b[i]);
	for(int i=1;i<=k;i++)base.a[i][k]=b[i],base.a[i+1][i]=-1;
	if(n<=k){
		printf("%lld",a[n]);
		return 0;
	}
	qpow(base,n-k);
	printf("%lld",ans.a[1][k]);
	return 0;
}
posted @ 2025-09-10 21:38  一班的hoko  阅读(3)  评论(0)    收藏  举报