解题思路
根据题意,金片只能从一根柱子上顺时针移动到下一个柱子上,而不能反过来移动,因此我们只需要考虑两种情况。
1、将n个金片移动到顺时针的下一个柱子上。所需的次数记为 move1[n]
2、将n个金牌移动到逆时针的上一个柱子上,相当于是顺时针移动两次。所需的次数记为 move2[n]
现在要做的是,推导 move1[n + 1] 和 move2[n + 1] 。
我们先看 move1[n + 1] 。不妨假设现在要将n + 1个金片从A柱子移动到B柱子,那么可以把过程拆分为几个步骤:
1、把n个金片从A移动到C,所需次数为 move2[n]。
2、将最下面的一个金片从A移动到B,记移动1次。
3、最后将C上的n个金片移动到B,所需次数为 move2[n]。
整理成式子就是 move1[n + 1] = move2[n] * 2 + 1
再看 move2[n + 1]。同样不妨假设现在要将n + 1个金片从A柱子移动到C柱子,那么可以把过程拆分为几个步骤:
1、把n个金片从A移动到C,所需次数为 move2[n]。
2、将最下面的一个金片从A移动到B,记移动1次。
3、将C上的n个金片移动到A,所需次数为 move1[n]。
4、步骤2中移动到B上的金片移动到C,记移动1次。
5、将A上的n个金片移动到C,所需次数为 move2[n]。
整理成式子就是 move2[n + 1] = move2[n] * 2 move1[n] + 2
推导出这两个公式后,写代码就很简单了。
注意初始状态:move1[1] = 1 , move2[1] = 2
以上的推导过程也可以看成是动态规划,两个式子就是动态转移方程。
#include <iostream> #include <vector> using namespace std; const int mod = 1000000007; int main() { int n; cin >> n; vector<long long> move1(n + 1); vector<long long> move2(n + 1); move1[1] = 1; move2[1] = 2; for(int i = 1; i < n; ++i) { move1[i + 1] = (move2[i] * 2 + 1) % mod; move2[i + 1] = (move2[i] * 2 + move1[i] + 2) % mod; } cout << move1[n] << " " << move2[n]; }