钥匙计数之一
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 N=3: 8 ");
- 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 ", i, a[i]);
- }
- return 0;
- }