一、题目
Problem Description
一把钥匙有N个槽,2<N<26槽深为1,2,3,4,5,6。每钥匙至少有3个不同的深度且相连的槽其深度之差不得为5。求这样的钥匙的总数。
Input
本题无输入
Output
对2<N<26,输出满足要求的钥匙的总数。
Sample Output
N=3: 104
N=4: 904
N=5: 5880
.
.
.
N=25: 8310566473196300280
二、题目分析
提交完本题后,颇觉有递推的味道。
出发点:构造结果ans[n]=num[1]+……+num[6];其中num[i]表示以i为最后一个槽的高度;计算出num[i],从而得出结果。
首先进行初始化分析,即n=3时。
“相连的槽其深度之差不得为5”——1,6这两个高度不能相邻;而2,3,4,5这四个高度等价,且之后n=4,5,……25的计算过程中均有此规律。即num[1]=num[6],num[2]=num[3]=num[4]=num[5],在写代码时注意到这点便可以不需要用到数组;
num[1]=num[6]=16;num[2,3,4,5]=18;
ans[3]=104;
(下面是重点)
再由n-1递推分析n的情况:
1、当前面n-1个排列是钥匙的排列,则
A、对2,3,4,5作为第n个高度来说都能满足题意,有num[2,3,4,5]=ans[n-1];
B、对1,6(1,6等价,记号不同而已)来说,第n-1个高度不能为6,1,即要去掉
几个不符合题意的组合;num[1]=ans[n-1]-num__[6](前n-1个中最后一个为6的个数,实际写代码时要用另一个数组保存)。同理 num[6]=ans[n-1]-num__[1](……)。也即num[1,6]=ans[n-1]-num__[6](……);
2、当前面n-1个排列不是钥匙的排列,则
A、对i(i=2,3,4,5)作为第n个高度来说能满足钥匙的要求,则说明前面n-1个排列里仅有两类高度,且与i不同,加上i就刚好3类高度满足题意。那么前面两类高度的选法总数是从其余5类高度里选出两类,即C(5,2),但1,6不能同时选,故组合数为
C(5,2)-1。 再看排列数,n-1个位置,每个位置可任选两类,但不能全部是同一类高度,故排列数2^(n-1)-2。
B、对i=1,6,同上面分析。因为1,6等价,所以我这里举i=1来说,前面两类高度里我有两种取法,选6和不选6。
对于选6,组合数是C(4,1)(剩下2,3,4,5任意选一);再看排列数,每个位置可任选两类,但不能全部是同一高度,且最后一个也即第n-1个位置处不能为6,也可换个说法,最后一个位置放i(i=2,3,4,5),前面n-2个位置任选6和i放,排列数4×(2^(n-2)-1)。前面不能全是和后面n-1的位置同一高度
对于不选6,组合数是C(4,2);再看排列数,每个位置可任选两类,且不能全部是同一类高度,排列数2^(n-1)-2。
把上面的组合数与排列数相乘便得到一种情况下的num[i]的值,所有情况的值相加便得到结果。
三,源代码
#include <stdio.h> #include <math.h> int main() { __int64 num[3],ans[26],t=16; int i; ans[3]=104; for(i=4;i<=25;i++) { num[1]=ans[i-1]; num[2]=ans[i-1]-t; num[1]+=9*((__int64)pow(2,i-1)-2); num[2]+=4*((__int64)pow(2,i-2)-1)+6*((__int64)pow(2,i-1)-2); ans[i]=4*num[1]+2*num[2]; t=num[2]; } for(i=3;i<=25;i++) { printf("N=%d: %I64d\n",i,ans[i]); } return 0; }