【HDU】1483钥匙计数

Problem Description

一把锁匙有N个槽,槽深为1,2,3,4。每锁匙至少有3个不同的深度且至少有1对相连的槽其深度之差为3。求这样的锁匙的总数。

Input

本题无输入

Output

对N>=2且N<=31,输出满足要求的锁匙的总数。

Sample Output

N=2: 0
N=3: 8
N=4: 64
N=5: 360
..
..
..
..
..
..
..

N=31: ...

注:根据Pku Judge Online 1351 Number of Locks或 Xi'an 2002 改编,在那里N&lt;=16

Author

ecjtu_zhousc

转载自:https://blog.csdn.net/u013533289/article/details/22978507

分析:

 

a[i]表示长度为i的合法的钥匙总数。
b[i]表示第i个槽为1或4时合法的长度为i的合法的钥匙总数。
c[i]表示:不合法的长度为i-1的钥匙X + 最后一个新槽1/4(1或者4的槽),能够构成合法的长度为i的钥匙时,不合法的长度为i-1的钥匙X的方案数

1、合法的长度为i-1的钥匙 + 任何1个新的槽,所构成的长度为i的钥匙一定是合法的,所以a[i]=a[i-1]*4

2、若不合法的长度为i-1的钥匙X + 最后一个新槽2/3(2或者3的槽),要构成合法的长度为i的钥匙,则X必定由1/4(1或者4的槽)的组合构成序列(原因在于后缀2或者3加上就成为钥匙的话,必然是没满足需要3个不同深度槽这一项,故X必然由1/4组成),但需要去除2种情况111....1111(全为1),444....444(全为4),所以
a[I]+=(2^(I-1)-2)*2(为什么是它,因为前i-1个槽均可以是1或4,有这么多种组合方式,减去上述两种特殊情况,即这两种特殊情况下,最后一个新槽为2/3时仍不能构成合法的长度为i的钥匙。之所以乘2,是因为最后一个新槽可以是2,也可以是3)。

3、若不合法的长度为i-1的钥匙X + 最后一个新槽1/4(1或者4的槽),要构成合法的长度为i的钥匙,设:x=Y(1/4) 即 长度为i-1的钥匙x=长度为i-2的钥匙y+第i-1个槽为1/4(1或者4的槽)
则要在不合法的长度为i-1的钥匙X加上最后1个新槽1/4(1或者4的槽)成为一个合法的长度为i的钥匙,
当且仅当第i-1位的槽是4/1时,加上第i位的1/4槽,才能满足。
(因为不合法的长度为i-1的钥匙X ,要么就不满足具有3个不同的槽,或不满足至少有1对相连的槽其深度之差为3,或同时不满足。要在加上最后1个新槽1/4(1或者4的槽)后成为长度为i的合法的钥匙,只可能是
A、前i-2位是1,2,3,4四种槽的任意组合+第i-1位的4+第i位的1
B、前i-2位是1,2,3,4四种槽的任意组合+第i-1位的1+第i位的4
C、在前两种组合中去掉下面两种情况--无法构成合法的长度为i的钥匙:
   前i-2位是1,4两种槽的任意组合+第i-1位的4+第i位的1
   前i-2位是1,4两种槽的任意组合+第i-1位的1+第i位的4
D、在前两种组合中去掉下面这种情况:
   因为在A情况下,“前i-2位是1,2,3,4四种槽的任意组合+第i-1位的4”包含了长度为i-1的,第i-1位为4的合法的长度为i-1的钥匙X
   在B的情况下“前i-2位是1,2,3,4四种槽的任意组合+第i-1位的1”包含了长度为i-1的,第i-1位为1的合法的长度为i-1的钥匙X
   但第3类的前提是“不合法的长度为i-1的钥匙X”,两者矛盾。因此,要减去第i-1个槽为1或4时合法的长度为i-1的合法的钥匙总数 即b[i-1]
 )
故第3类中,c[i]==(4^(i-2)-2^(i-2))* 2 - b[i-1];
  所以a[i]+=c[i]

4、修正b[i]
   b[i]表示第i个槽为1或4时合法的长度为i的合法的钥匙总数。
   在求得a[i-1]后可知长度为i-1的合法的钥匙总数。每种方案中增加第i位的1/4槽(1或者4的槽),总是b[i]中数据的一部分。即2*a[i-1]
   在求得c[i]后可知长度为i-1的不合法的钥匙 + 第i位的1/4槽(1或者4的槽)所能构成的合法的长度为i的第i位为1/4槽的钥匙总数,也是b[i]中数据的一部分。即c[i]
   故b[i]=2*a[i-1]+c[i]

代码:

#include<stdio.h>
#include<math.h>
int main()
{
	__int64 one[32]={0},two[32]={0},lock[32]={0};
	one[3]=2;
	lock[2]=0;
	lock[3]=8;
	printf("N=2: 0\n");
	printf("N=3: 8\n");
	for(int n=4;n<32;n++)
	{
	one[n]=(__int64)pow((float)4,n-2)-(__int64)pow((float)2,n-2)-one[n-1]+lock[n-1];
	two[n]=(__int64)pow((float)2,n-1)-2+lock[n-1];
	lock[n]=2*(one[n]+two[n]);
	printf("N=%d: %I64d\n",n,lock[n]);
	}
	getchar();
	return 1;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值