Covering HDU - 6185 (矩阵快速幂)

Covering

题目链接:HDU - 6185

题意:一个4*n的矩形广场,要用2*1的瓷砖和1*2的瓷砖铺满,问有几种铺瓷砖的方案;

之前做过一个类似的:

用1*2和2*1的瓷砖铺满2*n的广场,这道题的递推式是ans[n]=ans[n-1]+2*ans[n-2];

那么在看到这道题的时候也就想到了找递推式;

先写了个dfs找了n=1~10的结果:1, 5, 11, 36, 95, 281, 781, 2245, 6336, 18061;

1*5=5但5*5!=11;

2*5+1=11但2*11+5!=36;

......

36+11*5+5-1=95而且95+36*5+11-5=281

到此为止找到递推式ans[n]=ans[n-1]+5*ans[n-2]+ans[n-3]-ans[n-4];

找递推式的过程就是不断试验,在没有明显规律下,只能慢慢的试,运气好就对了,运气不好可能一直试不出来~~~

数据时1e18,所以想到用矩阵快速幂;构造一个矩阵A,使其满足下面式子

根据递推式和矩阵运算特点得出矩阵A:

矩阵A第一行是递推式的系数, 下边每行的1对应结果中ans[n-i]:根据第二行的运算得到ans[n-1], 第三行得到ans[n-2], 第四行得到ans[n-3];

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
long long n;
//注释部分是用来打表找递推式的程序;
//int vis[110][110];
//int ans, n;
//int ok(){
//	for(int i=0; i<n; i++){
//		if(vis[3][i]==0) return 0;
//	}
//	return 1;
//}
//void dfs(int x, int y){
//	if(x==4){
//		if(ok()){
//			ans++;
//		}
//		return;
//	}
//	if(y==n) dfs(x+1, 0);
//	if(y>n) return;
//	if(vis[x][y]) dfs(x, y+1);
//	else{
//		if(y+1<n&&vis[x][y+1]==0&&vis[x][y]==0){
//			vis[x][y]=vis[x][y+1]=1;
//			dfs(x, y+2);
//			vis[x][y]=vis[x][y+1]=0;
//		}
//		if(x+1<4&&vis[x+1][y]==0&&vis[x][y]==0){
//			vis[x][y]=vis[x+1][y]=2;
//			dfs(x, y+1);
//			vis[x][y]=vis[x+1][y]=0;
//		}
//	} 
//}
struct node{
	long long a[5][5];
};
const long long mod=1e9+7;
node mul(node x, node y){
	node z;
	memset(z.a, 0, sizeof(z.a));
	for(int i=0; i<4; i++){
		for(int j=0; j<4; j++){
			for(int k=0; k<4; k++)
			z.a[i][j]+=x.a[i][k]*y.a[k][j];
			z.a[i][j]%=mod;
		}
	}
	return z;
}
node _pow(node x, node y, long long p){
	node z;
	memset(z.a, 0, sizeof(z.a));
	for(int i=0; i<4; i++){
		z.a[i][i]=1;
	}
	while(p){
		if(p&1){
			z=mul(z, x);
		}
		x=mul(x, x);
		p>>=1;
	}
	z=mul(z, y);
	return z;
}
int main(){
//	while(cin >> n){
//		memset(vis, 0, sizeof(vis));
//		ans=0;
//		dfs(0, 0);
//		cout << "-------" << ans << endl;
//	}
	while(~scanf("%lld", &n)){
		if(n==1) printf("1\n");
		else if(n==2) printf("5\n");
		else if(n==3) printf("11\n");
		else if(n==4) printf("36\n");
		else {
			node x;
			memset(x.a, 0, sizeof(x.a));
			x.a[0][0]=1;
			x.a[0][1]=5;
			x.a[0][2]=1;
			x.a[0][3]=-1;
			x.a[1][0]=1;
			x.a[2][1]=1;
			x.a[3][2]=1;
			node y;
			memset(y.a, 0, sizeof(y.a));
			y.a[0][0]=36;
			y.a[1][0]=11;
			y.a[2][0]=5;
			y.a[3][0]=1;	
			node z;
			z=_pow(x, y, n-4);
			printf("%lld\n", (z.a[0][0]+mod)%mod);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Sirius_han/article/details/80582890
今日推荐