鑰匙計數之一
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2113 Accepted Submission(s): 1006
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<=16
解析:
一個遞推的重排列問題
a[i]來表示長度爲i的槽是鑰匙的情況
若a[i-1]合法,則第i個可以是1,2,3,4 => a[i]=a[i-1]*4;
若a[i-1]不合法,有兩種情況:
1.n-1個裏有相鄰相差3的槽,且不合法,n-1個只能是1,4全排列,要要去掉全爲1或者全爲4的情況
2.n-1個裏沒有相鄰相差3的槽,我們用b[n]來表示這種情況且合法的
呢麼要讓n個合法,n-1一定是1或者4,n-2個可以是任意情況:4^(n-2),有(1,4),(4,1)兩種情況
2*(4^(n-2)),這2*(4^(n-2))個裏要減去n-2個裏全爲1或者4的情況: 2^(n-2),還要減去n-1裏n-1位是(1或者4)
且本身就合法的情況b[n-1],
ac:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int i;
ll temp,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;//n-1已經合法
a[i]+=(ll)(2*(pow(2,i-1)-2));//n-1序列全爲1,4
temp=((ll)pow(4,i-2)-(ll)pow(2,i-2))*2-b[i-1];//結尾爲(1,4)且合法
a[i]+=temp;
b[i]=a[i-1]*2+temp;//n個序列,結尾爲1,4且合法,加上n-1個序列且合法的一半(1或者4)
printf("N=%d: %I64d\n",i,a[i]);
}
return 0;
}
ac: