Problem Description
一把锁匙有N个槽,槽深为1,2,3,4。每锁匙至少有3个不同的深度且至少有1对相连的槽其深度之差为3。求这样的锁匙的总数。
Input
本题无输入
Output
对N>=2且N<=31,输出满足要求的锁匙的总数。
Sample Input
无
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
思路:一个递推的重排列问题,状压DP也能做,但还是果断偷懒用递推了。。。
用 a[i] 来存储为 i 个槽时的钥匙数,假设一个钥匙有 n 个槽
若该钥匙的前 n-1 个槽合法,则第 n 个槽的深度可为任意深,此时有 a[n]=4*a[n-1]
若该钥匙的前 n-1 个槽不合法,有以下两种情况:
1)前 n-1 个有相邻且相差深度为3的槽,但只有两种深度,此时由于有相邻且相差深度3的槽,因此只能为1、4深度的全排列,再减去只有深度为 1、4 的情况,即有 a[n]=2*(2^(n-1)-2)
2)前 n-1 个没有相邻且相差深度3的槽,由于相差深度为3的槽只有1、4,因此如果想要让其合法,只有最后一个排列是1或4时才可,因此当第 n 个确定时,第 n-1 个槽也就确定了
用 b[n-1] 来表示一个 n-1 的排列中符合该种情况且合法的状态数,即用 b[n-1] 表示最后一个数是1或4,去掉后这些排列中无相邻且相差深度为3的槽
由于最后两个 n、n-1 均可确定,因此前 n-2 个槽可为任意深度,即有 4^(n-2) 个,再减去只有深度为 1、4 的情况,即减去 2^(n-2) 个
此时,每种情况均可确定,但由于最后 n 位置的槽可能为 1 或 4,因此要乘以 2,再减去前 n-1 项合法的答案即 b[n-1]
即有:a[n]=(2*( 4^(n-2)-2^(n-2) ) )*2-b[n-1]
Source Program
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstdlib>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<vector>
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define N 32
#define MOD 10007
#define E 1e-6
#define LL long long
using namespace std;
LL a[N],b[N];
int main()
{
a[2]=0;
a[3]=8;
b[2]=0;
b[3]=4;
for(int i=2;i<=31;i++){
for(int j=4;j<=i;j++){
a[i]=4*a[i-1];
a[i]+=2*(LL)(pow(2,i-1)-2);
a[i]+=2*(LL)(pow(4,i-2)-(LL)pow(2,i-2))-b[i-1];
b[i]=2*a[i-1]+2*(LL)(pow(4,i-2)-(LL)pow(2,i-2))-b[i-1];
}
cout<<"N="<<i<<": "<<a[i]<<endl;
}
return 0;
}