P4285 [SHOI2008]汉诺塔 题解 (乱搞)
题目链接
解题思路
提供一种打表新思路
先来证明一个其他题解都没有证明的结论:\(ans[i]\)是可由\(ans[i-1]\)线性递推的。
(\(ans[i]\)表示\(i\)个盘子全部移走的步数)
感谢keytoyzi神仙的神仙思路
首先,在最初两层移动的时候,遵循的移动顺序规则是题中所给的顺序。
在\(n\)个盘子都在\(A\)柱的时候,我们是怎么做的呢?
先把前\(n-1\)个盘子按照遵循初始顺序规则的方法移动到\(B\)或\(C\);
再对第\(n\)个盘子进行操作;
再进行某些操作(后文会展开);
最后所有盘子移动到\(B\)或者\(C\)。
这等价于:
每一层对应一个新规则,把前\(n-1\)层盘子看做一层,那就相当于按照这个新的规则移动一个两层的东西。
这个新规则是啥意思呢?光说理论太难以理解,上图:
解释一下:\(n-1\)代表前\(n-1\)个盘子,这些盘子根据初始规则可能移动到\(B\)或者\(C\),而把他们看做一个整体后,相当于上图的遵循初始规则的移动方式,而这种新的移动方式,就是一个新的规则。
再来两张状态转移的图:
(单箭头表示这一步操作优先级高于另一侧)
解释一下这张图。
刚开始对于前\(n\)个盘子形成的新规则:
\(AB>AC\),\(BC>BA\),\(CA>CB\)。
根据这个规则进行第\(n+1\)层的操作:(以\(A \to C\)为例)
先把\(A\)上的前\(n\)个盘子扔到\(B\)上;(\(A(n)\))
再把\(A\)最底下的第\(n+1\)个盘子扔到\(C\)上;(\(1\))
再把扔到\(B\)上的前\(n\)个盘子扔到\(C\)上。(\(B(n)\))
故总步骤数为\(A(n)+1+B(n)\)。
同理,那么这就给出了一组递推关系。
易得,如果\(n\)满足左图,则\(n+1\)满足右图;
如果\(n\)满足右图,则\(n+1\)满足左图。
也就是说,这两张图中的状态可以互相转换。
又,\(ABC\)是等价的,故这张图对应了一种可能的答案(答案\(1\))。
这张图更复杂一些,不过实质和刚刚的相同。
以\(A\to B\)为例。
先把\(A\)上的前\(n\)个盘子扔到\(B\)上;(\(A(n)\))
再把\(A\)最底下的第\(n+1\)个盘子扔到\(C\)上;(\(1\))
再把\(A\)上的这n个盘子扔回\(A\)上;(\(B(n)\))
再把\(C\)上的第n+1个盘子扔到\(B\)上;(\(1\))
再把\(A\)上的那\(n\)个盘子扔回\(B\)上。(\(B(n)\))
故总步骤数为\(A(n)+1+B(n)+1+B(n)\)。
同理易得,如果n满足左图,则n+1满足右图;
如果\(n\)满足右图,则\(n+1\)满足左图。
也就是说,这两张图中的状态还是可以互相转换。
而在这张图上,\(AB\)是等价的,\(C\)是另一种情况,故这张状态图对应了两种可能的答案:
\(AB\)对应的状态为初始\(A\)柱(答案\(2\))
或
\(C\)对应的状态为初始\(A\)柱(答案\(3\))。
好,那么现在对应这三种情况做一种简单的分析。
对于第一种答案:
\(ABC\)等价,故\(A(n)=B(n)=C(n)=ans_1[n]\)
由图中的递推公式,\(ans_1[n+1]=ans_1[n]*2+1\)
对于第二种答案:
\(AB\)等价,\(A(n)=B(n)=ans_2[n]\)
\(ans_2[n+1]=ans_2[n]*3+2\)
对于第三种答案:
\(AB\)等价,\(A(n)=B(n)=ans_2[n]\)
\(ans_3[n+1]=ans_2[n]+ans_3[n]+1\)
这是一个线性表达式。
证毕。
所以,我们只需要知道移动一个盘子、两个盘子、三个盘子的情况,即可知道递推公式进而求解。
手动模拟打表,容易得到以下结果:
(\(ans[i]\)表示i个盘子全部移走的步数)
一个盘子:
\(ans[1]=1\)
两个盘子:
\((1)AB>AC\)
①\(BC>BA\),\(ans[2]=3\)
②\(BC<BA\),\(ans[2]=5\)
\((2)AB<AC\)
这里可以看做把\(BC\)柱子换了个位置
①\(ans[2]=3\):原\(BC>BA\),把\(BC\)换了个位置后变成\(CB>CA\)
②\(ans[2]=5\):原\(BC<BA\),同理变成\(CB<CA\)
三个盘子:
\((1)AB>AC\)
①\(BC>BA\)
\((i)CB>CA\),\(ans[3]=9\)
\((ii)CB<CA\),\(ans[3]=7\)
②\(BA>BC\)
\(ans[3]=17\)
\((2)AB<AC\)
同理,不再赘述
下附递推AC代码:
#include<stdio.h>
char a[4];
int seq[3][3];
long long ans[40];
int main(){
int i,n;
scanf("%d",&n);
for(i=0;i<6;i++){
scanf("%s",a);
seq[a[0]-'A'][a[1]-'A']=6-i;
}
if(seq[0][1]>seq[0][2]){//AB>AC
if(seq[1][2]<seq[1][0]){//BC<BA
ans[2]=5;ans[3]=17;
}else{
if(seq[2][0]>seq[2][1]){//CA>CB
ans[2]=3;ans[3]=7;
}else{
ans[2]=3;ans[3]=9;
}
}
}else{//AB<AC
if(seq[2][1]<seq[2][0]){//CB<CA
ans[2]=5;ans[3]=17;
}else{
if(seq[1][0]>seq[1][2]){//BA>BC
ans[2]=3;ans[3]=7;
}else{
ans[2]=3;ans[3]=9;
}
}
}
ans[1]=1;
int b=(ans[2]*ans[2]-ans[1]*ans[3])/(ans[2]-ans[1]);
int k=(ans[2]-b)/cnt1;
for(i=4;i<=n;i++)ans[i]=ans[i-1]*k+b;
printf("%lld",ans[n]);
return 0;
}
其实,这已经没有必要写成递推形式了。我们在讨论三种答案的时候,其实已经可以手算算出三种情况的O(1)表达式了。
来一发最短AC代码
#include<stdio.h>
#include<math.h>
typedef long long ll;
char a[4];
int s[9],p,n,i=6;
ll f(int x){
if(x==1)return (ll)2*pow(3,n-1)-1;
if(x)return (ll)pow(2,n)-1;
return (ll)pow(3,n-1);
}
int main(){
scanf("%d",&n);
while(i--)scanf("%s",a),s[(a[0]-'A')*3+a[1]-'A']=i;
if(s[1]>s[2]){
if(s[5]<s[3])p=1;
else if(s[6]>s[7])p=2;
}else if(s[7]<s[6])p=1;
else if(s[3]>s[5])p=2;
printf("%lld",f(p));
return 0;
}
P4285 [SHOI2008]汉诺塔 题解 (乱搞)的更多相关文章
- BZOJ1019 汉诺塔/洛谷P4285 [SHOI2008]汉诺塔
汉诺塔(BZOJ) P4285 [SHOI2008]汉诺塔 居然是省选题,还是DP!(我的DP菜得要死,碰见就丢分) 冥思苦想了1h+ \(\to\) ?! 就是普通的hanoi NOI or HNO ...
- bzoj1019 / P4285 [SHOI2008]汉诺塔
P4285 [SHOI2008]汉诺塔 递推 题目给出了优先级,那么走法是唯一的. 我们用$0,1,2$代表$A,B,C$三个柱子 设$g[i][x]$为第$x$根柱子上的$i$个盘子,经过演变后最终 ...
- P4285 [SHOI2008]汉诺塔
题目描述 汉诺塔由三根柱子(分别用A.B.C表示)和n个大小互不相同的空心盘子组成.一开始n个盘子都摞在柱子A上,大的在下面,小的在上面,形成了一个塔状的锥形体. 对汉诺塔的一次合法的操作是指:从一根 ...
- 【BZOJ1019】[SHOI2008]汉诺塔(数论,搜索)
[BZOJ1019][SHOI2008]汉诺塔(数论,搜索) 题面 BZOJ 洛谷 题解 首先汉诺塔问题的递推式我们大力猜想一下一定会是形如\(f_i=kf_{i-1}+b\)的形式. 这个鬼玩意不好 ...
- 【bzoj1019】[SHOI2008]汉诺塔
1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1427 Solved: 872[Submit][Status] ...
- bzoj1019: [SHOI2008]汉诺塔(动态规划)
1019: [SHOI2008]汉诺塔 题目:传送门 简要题意: 和经典的汉诺塔问题区别不大,但是题目规定了一个移动时的优先级: 如果当前要从A柱子移动,但是A到C的优先级比A到B的优先级大的话,那就 ...
- 1019: [SHOI2008]汉诺塔
1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1495 Solved: 916[Submit][Status] ...
- bzoj1019 [SHOI2008]汉诺塔
1019: [SHOI2008]汉诺塔 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 1030 Solved: 638[Submit][Status] ...
- BZOJ 1019: [SHOI2008]汉诺塔( dp )
dp(x, y)表示第x根柱子上y个盘子移开后到哪根柱子以及花费步数..然后根据汉诺塔原理去转移... ------------------------------------------------ ...
随机推荐
- 排序算法 以及HKU的一些数据结构 相关题目 以及 K叉树,二叉树 排列
冒泡排序.选择排序.快速排序.插入排序.希尔排序.归并排序.基数排序以及堆排序,桶排序 https://www.cnblogs.com/Glory-D/p/7884525.html https://b ...
- Java之一个整数的二进制中1的个数
这是今年某公司的面试题: 一般思路是:把整数n转换成二进制字符数组,然后一个一个数: private static int helper1(int i) { char[] chs = Integer. ...
- 手撕 part1
1.宏定义三个数最大值 挺有意思 max((a), (b), (c)) (a) > (b)? ((a) > (c)? (a) : (c)) ((b) > (c)? (b) : (c) ...
- BZOJ1001 狼抓兔子(网络流转最短路:对偶图)
题意: 给一个如图形式的\(n*m\)的方格,从左上走到右下,给出边权,问分成两块所需的最小代价.\(n,m\leq1000\). 思路: 显然是个最小割,但是\(O(n^2m)\)的复杂度很高,虽然 ...
- js sort map by key
js sort map by key Map map to array // Array.from() Object let obj = {}; for(let key of Object.keys( ...
- 前端 & 技术团队 TL & 如何面试 & 如何带人
前端 & 技术团队 TL & 如何面试 & 如何带人 面试 带人 作为 TL,深度了解你的团队非常重要,要去了解每个人的想法是什么,他的诉求是什么,他目前的状态怎么样,以及对他 ...
- windwos创建和删除服务
创建 >sc create <service name> type=kernel binpath="C:\hsys.sys" 删除 win+r 输出 regedi ...
- Mybatis-03 配置解析
Mybatis-03 配置解析 配置解析 1.核心配置文件 mybatis-config.xml: configuration(配置) properties(属性) settings(设置) type ...
- 新手如何通过内存和NGK DeFi Baccarat进行组合投资?
区块链市场在2020年迎来了大爆发,资本市场异常火热.无论是内存,还是DeFi,都无疑是这个火爆的区块链市场中的佼佼者.通过投资内存和DeFi,很多投资者都已经获取了非常可观的收益,尝到了资本市场带来 ...
- Python学习笔记_生成验证码
import random def verification_code(): num = [str(x) for x in range(10)] # 列表生成器0-9 upper = [chr(x) ...