2018icpc焦作赛区网络预选赛 L Poor God Water(矩阵快速幂)

题意:

现在有长度为n的方格,每个方格只能放鱼,肉,巧克力,并且连续三个方格要满足以下条件:
1.三个方格不能是同一种食物
2.巧克力放中间时左右两个方格的食物必须相同
3.三个方格的最左和最右不能同时为巧克力

题解:

当前格子只与前面两个各自有关,然后枚举递推,直接9*9的矩阵快速幂即可。
比赛的时候把递推式给枚举出来了…居然没发现是一个矩阵快速幂…

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
const int N=9;
struct node
{
	long long a[N][N];
	void init0()
	{
		memset(a,0,sizeof(a));
	}
	void init1()
	{
		init0();
		for(int i=0;i<N;i++)
			a[i][i]=1;
	}
	void init()
	{
		init0();
		a[0][3]=1,a[0][6]=1;
		a[1][0]=1,a[1][3]=1,a[1][6]=1;
		a[2][0]=1,a[2][3]=1;
		a[3][1]=1,a[3][4]=1,a[3][7]=1;
		a[4][1]=1,a[4][7]=1;
		a[5][1]=1,a[5][4]=1;
		a[6][2]=1,a[6][8]=1;
		a[7][5]=1,a[7][8]=1;
		a[8][2]=1,a[8][5]=1;
	}
	node operator*(const node&b)const
	{
		node temp;
		temp.init0();
		for(int i=0;i<N;i++)
			for(int j=0;j<N;j++)
				for(int k=0;k<N;k++)
					temp.a[i][j]=(temp.a[i][j]+a[i][k]*b.a[k][j]%mod)%mod;
		return temp;
	}
};
node qpow(long long b)
{
	node ans;
	node ju;
	ju.init();
	ans.init1();
//	for(int i=0;i<N;i++)
//	{
//		for(int j=0;j<N;j++)
//		{
//			cout<<ju.a[i][j]<<" ";
//		}
//		cout<<endl;
//	}
	while(b>0)
	{
		if(b&1) ans=ans*ju;
		ju=ju*ju;
		b>>=1;
	}
	return ans;
}

int main()
{
	int T,i,j,k,m;
	long long n;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%lld",&n);
		long long ans=0;
		if(n==1)
		{
			cout<<3<<endl;
			continue;
		}
		else if(n==2)
		{
			cout<<9<<endl;
			continue;
		}
		node Ans=qpow(n-2);
		for(i=0;i<N;i++)
		{
			for(j=0;j<N;j++)
			{
				ans=(ans+Ans.a[i][j])%mod;
//				cout<<Ans.a[i][j]<<" ";
			}
//			cout<<endl;
		}
				
		printf("%lld\n",ans);
	}
 } 

Q.E.D.