好像并没有矩阵快速幂的题解,那我来写一篇
题目分析
对于每两盏灯,只考虑右灯变化,分为四种情况:
左灯为 \(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;
}
标签:ch,int,题解,矩阵,cdots,Blink,P2203,右灯,vdots
From: https://www.cnblogs.com/MooSheng/p/17621272.html