P2203 Blink 题解

发布时间 2023-08-10 19:05:17作者: Mo默Sh笙

好像并没有矩阵快速幂的题解,那我来写一篇

题目分析

对于每两盏灯,只考虑右灯变化,分为四种情况:

左灯为 \(1\),右灯为 \(1\),右灯变为 \(0\)

左灯为 \(0\),右灯为 \(0\),右灯不变,为 \(0\)

左灯为 \(1\),右灯为 \(0\),右灯变为 \(1\)

左灯为 \(0\),右灯为 \(1\),右灯不变,为 \(1\)

设第 \(i\) 盏灯状态为 \(s[i]\)

不难发现:

\[s[i] = s[i-1] \oplus s[i] \]


可以构造如下 \(N\times N\) 递推矩阵,用于进行递推:

\(\begin{bmatrix} 1 & 1 & 0 & \cdots & 0 & 0 & 0\\ 0 & 1 & 1 & \cdots & 0 & 0 & 0\\ 0 & 0 & 1 & \cdots & 0 & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \vdots &\\ 0 & 0 & 0 & \cdots & 1 & 1 & 0\\ 0 & 0 & 0 & \cdots & 0 & 1 & 1\\ 1 & 0 & 0 & \cdots & 0 & 0 & 1\\ \end{bmatrix}\)

(灯环形排列,需要头尾相接)


举个例子,当 \(N=5\) 时,矩阵即为:

\(\begin{bmatrix} 1 & 1 & 0 & 0 & 0\\ 0 & 1 & 1 & 0 & 0\\ 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 0 & 1 & 1\\ 1 & 0 & 0 & 0 & 1\\ \end{bmatrix}\)

递推矩阵推出来后,直接矩阵快速幂即可。


朴实无华的代码

#include<bits/stdc++.h>
using namespace std;
#define int long long//十年OI一场空,不开long long见祖宗
inline int read(){int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}return x;}
const int N=20;
const int p=2;
int n,m;
int s[N];
struct MS
{
	int c[N][N];
	int n,m;
};
MS operator *(const MS &a,const MS &b)//矩阵乘法
{
	MS c;
	c.n=a.n;
	c.m=b.m;
	for(int i=1;i<=a.n;i++)
		for(int j=1;j<=b.m;j++)
			c.c[i][j]=0;
	for(int i=1;i<=a.n;i++)
		for(int j=1;j<=b.m;j++)
			for(int k=1;k<=a.m;k++)
				c.c[i][j]=(c.c[i][j]+a.c[i][k]*b.c[k][j]%p)%p;
	return c;
}
MS fpow(MS a,int k)//矩阵快速幂
{
	MS e;
	e.n=n;
	e.m=m;
	for(int i=1;i<=n;i++) e.c[i][1]=s[n-i+1];
	while(k>0)
	{
		if(k&1) e=a*e;
		a=a*a;
		k>>=1;
	}
	return e;
}
MS init()//递推矩阵构造
{
	MS a;
	a.n=n;
	a.m=n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			a.c[i][j]=0;
	for(int i=1;i<=n;i++)
	{
		a.c[i][i]=1;
		a.c[i][i+1]=1;
	}
	a.c[n][1]=1;//头尾相接
	return a;
}
MS a;
signed main()
{
	int k;
	m=1;
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++) s[i]=read();
	a=init();
	MS ans=fpow(a,k);
	for(int i=n;i>=1;i--)
	printf("%lld\n",ans.c[i][1]);
	return 0;
}