1. 程式人生 > >【HDU】1483鑰匙計數

【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

分析:

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;
}