这个题目主要是数学推理。
假设one[i],two[i],three[i],four[i]分别表示一共有i个槽的情况下第一个槽为1、2、3、4的情况,Lock[i]表示有i个槽的情况下锁匙的个数,容易得到Lock[i] = one[i] + two[i] + three[i] + four[i]。另外可以知道one[i]和four[i]的情况是一样多的,因为对于所有的第一个槽为1的合法情况,如果将其中的1全部变为4,4全部变为1,必然也是合法的,这样对于每一个第一个槽为1的情况必然对应着一个第一个槽为4的情况,同理对于所有的第一个槽为4的情况也必然有一个且仅有一个第一个槽为1的情况与之对应,所以可以得出结论one[i] = four[i];相同的分析方法可以得到two[i] = three[i];所以可以得到Lock[i] = 2 * one[i] + 2 *two[i];
关于one[i]的计算可以分为以下两种情况:(1)第一个槽为1不影响后面(2)第一个槽为1对后面的有影响。对于第一种情况总的个数为one[i-1] + two[i-1] + three[i-1] + four[i-1];
对于第二种情况可以认为如果第一位不是1的话那么序列就是非法的,在这种情况下第二位必然为4(如果第二位不为4的话,那么第一位为1就对后面序列的合法性没有影响)。
在第一位为1第二位为4确定的情况下一共有4^(i-2)种情况,在这种情况下需要去掉后面的i-2位只有1或者4的情况,这种情况个数为2^(i-2),另外还要去掉在第二位为4的情况下后面的i-1位合法的情况four[i-1],也即one[i-1];所以第二种情况下总的次数为4^(i-2) - one[i-1] -2^{i-2)。
综上所述:one[i] = one[i-1] + two[i-1] + three[i-1] + four[i-1] + 4 ^ (i-2) - one[i-1] -2^(i-2)。
关于two[i]的计算和one[i]的计算类似,也分为两种情况,第一种情况是相同的,下面对第二种情况进行分析:计算去掉第一位的2之后,后面是非法序列的个数。如果去掉了第一位的2之后后面的序列非法则表明后卖的序列仅由1和4组成,这种情况的个数为2^(i-1),但是要去掉全部为1和全部为4的两种情况,所以总的数量为2^(i-1) -2.
根据上面的分析可以得出Lock[i]的递推式:Lock[i] = 6 * one[i-1] + 8 * two[i-1] + 2 * 4^(i-2) + 2 * 2^(i-2) -4 。
下面附上AC代码:
#include <stdio.h>
#include <math.h>
const int N = 32;
int main(){
__int64 one[N],two[N],Lock[N];
one[2] = 0;two[2] = 0;Lock[2] = 0;
for(int i=3;i<N;i++){
one[i] = one[i-1] + 2 *two[i-1] + (__int64)pow((double)4,i-2) - (__int64)pow((double)2,i-2);
two[i] = 2 * one[i-1] + 2 * two[i-1] +(__int64)pow((double)2,i-1) -2;
Lock[i] = 2 * one[i] + 2 * two[i];
}
for(int i=2;i<N; i++){
printf("N=%d: %I64d\n",i,Lock[i]);
}
return 0;
}