鑰匙計數之一
Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java/Other)
Total Submission(s) : 1 Accepted Submission(s) : 1
Font: Times New Roman | Verdana | Georgia
Font Size: ← →
Problem Description
Input
Output
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<=16
Author
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 ()
- {
- int i;
- __int64 c[32], a[32], b[32]; //b[i]記錄以1 4結尾的數
- a[2] = 0;
- a[3] = 8;
- b[2] = 0;
- b[3] = 4;
- printf ("N=2: 0\nN=3: 8\n");
- for (i = 4; i <= 31; i++)
- {
- a[i] = a[i - 1] * 4;
- a[i] += (__int64) pow (2,i) - 4; //以2 3 結尾的
- c[i] = ((__int64) pow (4,i-2) - (__int64) pow (2, i - 2)) * 2 - b[i - 1];
- a[i] += c[i];
- b[i] = a[i - 1] * 2 + c[i];
- printf ("N=%d: %I64d\n", i, a[i]);
- }
- return 0;
- }