洛谷P4910 帕秋莉的手环

洛谷题目

本题描述较为复杂,这里简单描述一下。

把一个长度为 \(n\) 的环用金色和绿色染色,求出有多少种染色方法使得相邻两个点必有一个是金色。

矩阵快速幂优化dp

先考虑如何 \(dp\),用 \(dp_{i,0}\) 表示第 \(i\) 个点为金色的方案数,\(dp_{i,1}\) 表示第 \(i\) 个点为绿色的方案数,那么

\( \begin{cases} dp_{i,0}=dp_{i-1,0}+dp_{i-1,1}& \\ dp_{i,1}=dp_{i-1,1}& \\ \end{cases} \)

因为如果 \(i\) 为金色,那么 \(i-1\) 两种颜色都可以,如果 \(i\) 为绿色,那么 \(i-1\) 只能为金色。

注意:因为这是一个环,所以要分别讨论第1个是金色或绿色的情况。

  • 如果是金色,那么 \(dp_{i,0}=1\),第 \(n\) 个点两种颜色都可以,所以答案是 \(dp_{n,0}+dp_{n,1}\)

  • 如果是绿色,那么 \(dp_{i,1}=1,\)\(n\) 个只能是金色,所以答案是 \(dp_{n,0}\)

最后加起来取模就可以了。

接下来考虑如何优化。

因为第 \(i\) 个点的答案只取决余 \(i-1\),所以可以用矩阵快速幂。

不难发现

\[\begin{bmatrix} dp_{i-1,0} & dp_{i-1,1} \\ 0 & 0 \end{bmatrix} \quad × \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \quad = \begin{bmatrix} dp_{i,0} & dp_{i,1} \\ 0 & 0 \end{bmatrix} \quad \]

那么这道题就做完了。

#include<iostream>
#include<cstdio>
#include<cstring>
#define int long long	//注意这里 

using namespace std;

const int modd=1e9+7;
struct matrix
{
	int num[3][3];
	matrix()
	{
		memset(num,0,sizeof(num));
	}
	matrix operator * (const matrix &that) const	//矩阵乘法 
	{
		matrix r;
		for(int i=1; i<=2; i++)
			for(int j=1; j<=2; j++)
				for(int k=1; k<=2; k++)
					r.num[i][j]=(r.num[i][j]+num[i][k]*that.num[k][j]%modd)%modd;
		return r;
	}
	matrix operator ^ (int p)	//矩阵快速幂 
	{
		matrix r,a;
		memcpy(a.num,num,sizeof(num));
		for(int i=1; i<=2; i++)
			r.num[i][i]=1;
		for(; p; p>>=1,a=a*a)
			if(p&1) r=r*a;
		return r;
	}
};

matrix base;	//转移矩阵 
signed main()
{
	base.num[1][1]=base.num[1][2]=base.num[2][1]=1;
	int T;
	scanf("%lld",&T);
	while(T--)
	{
		int n,ans;
		matrix A,B;
		scanf("%lld",&n);
		A.num[1][1]=1;	//第1个点是金色的初始矩阵 
		B.num[1][2]=1;	//第1个点是绿色 
		A=A*(base^(n-1));
		B=B*(base^(n-1));
		ans=(A.num[1][1]+A.num[1][2]+B.num[1][1])%modd;
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2020-05-25 23:41  Acestar  阅读(114)  评论(0编辑  收藏  举报