【递推】多米诺骨牌

【题目描述】

Jzabc对多米诺骨牌有很大的兴趣,然而他的骨牌比较特别,只有黑的和白的。他觉得如果存在连续三个骨牌是同种颜色的,那这个骨牌排列就是不美观的。现在他有N个骨牌要排列,他想知道不美观的排列的个数。他想请你帮忙进行统计不美观排列的个数。

【输入格式】

只有一个正整数,即要排列的骨牌的个数。

【输出格式】

一个数,即不美观的排列的个数。

【输入样例】

4

【输出样例】

6

解释:有6中不美观的排列。

【数据规模】

对于20%的数据,满足N<=60

对于50%的数据,满足N<=600

对于100%的数据,满足N<=10000

【分析】

通过枚举可以发现有类似于斐波那契数列的规律。

递推加高精解决。

(简单的证明:)

每一个状态都有前面的状态推来。

如图




以i,j,k为例,i,j是前面的牌,k是等待加的牌。

那么k有两种加法。

1、如果k与j颜色不同,那么一定是美观的排列,直接把j的美观排列的个数加在k上。

2、如果k与j颜色相同, 

   (1)当j与i颜色不同。则k与j是等价的,即加上与j相同的k后,美观的数目没有增加。仍等于j的数目,而j等于什么呢?等于i。所以加上i中美观的数目。

   (2)当i与j颜色相同。排列是不美观的,不考虑。

所以得出递推式:f[i]=f[i-1]+f[i-2];

【代码】

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define mo 100000000
using namespace std;
int tol,n;
struct node
{
	int a[1010];
}f[20010];
int st[1010];
void jia(int n1,int n2)
{
	for (int i=1;i<=1009;i++)
	 {
	 	f[n1].a[i]+=f[n2].a[i];
	 	if (f[n1].a[i]>=mo)
	 	{
	 		f[n1].a[i+1]+=(f[n1].a[i]/mo);
	 		f[n1].a[i]%=mo;
	 	}
	 }
}
void cheng(int n)
{
    int hu[1010];
	st[1]=1;
	for(int i=1;i<=n;i++)
    {
        memset(hu,0,sizeof(hu));
        for (int j=1;j<=1009;j++)
	  { 
	   st[j]*=2;
	   st[j]+=hu[j];
	   if (st[j]>=mo)
	    {
	    	hu[j+1]+=(st[j]/mo);
	    	st[j]%=mo;
	    }
	   }
    }
      return ;
}
void jian()
{
	for (int i=1;i<=1009;i++) 
	{
	  st[i]-=f[n].a[i];
	  if (st[i]<0)
		{
		  st[i]+=mo;
		  st[i+1]--; 	
		}
    }
	return;
}
int main()
{   
    freopen("domino.in","r",stdin);
    freopen("domino.out","w",stdout);
	scanf("%d",&n);
	cheng(n);
    f[1].a[1]=2;
    f[2].a[1]=4;
    for (int i=3;i<=n;i++)
     {
     	jia(i,i-1);
     	jia(i,i-2);
     }
    jian();
    int ii=1009;while (st[ii]==0) ii--;
    cout<<st[ii]; ii--;
    for (int i=ii;i>=1;i--) printf("%.8d",st[i]);
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值