杭电OJ 1438:钥匙计数之一

43 篇文章 0 订阅
13 篇文章 0 订阅

这个题目主要是数学推理。

假设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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值