题意:
《具体数学》第一章的练习题中有这个问题。把汉诺塔问题加上了只能从一个盘子向顺时针的下一个盘子移动的限制。
思路:
f(n)=把n个盘子移到下一个盘子需要的步数
h(n)=把n个盘子移动下下个盘子需要的步数
求得递推关系式后得到系数矩阵,把(f(n) h(n) 1)放在一个列向量中作为变量矩阵。
#include<bits/stdc++.h>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
#define in_bound(l, r, i) (l)<=(i)&&(i)<(r)
#define PB push_back
typedef long long LL;
const int inf = INT_MAX/2;
const LL Mod = (LL)(1e9+7);
struct mat {
LL m[3][3];
};
mat mul(mat &a, mat &b) {
mat c;
memset(&c, 0, sizeof(c));
rep(i, 0, 2) rep(j, 0, 2) rep(k, 0, 2) c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j]%Mod)%Mod;
return c;
}
mat fast_pow(mat &src, int n) {
mat ans, x = src;
ans.m[0][0] = 1;ans.m[0][1] = 0;ans.m[0][2] = 0;
ans.m[1][0] = 0;ans.m[1][1] = 1;ans.m[1][2] = 0;
ans.m[2][0] = 0;ans.m[2][1] = 0;ans.m[2][2] = 1;
while (n) {
if (n&1) ans = mul(x, ans);
x = mul(x, x);
n >>= 1;
}
return ans;
}
void print(mat & A) {
cout << "print mat: \n";
rep(i, 0, 2) {rep(j, 0, 2) cout << A.m[i][j] << ' ';cout << endl;}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
mat A;
A.m[0][0] = 0;A.m[0][1] = 2;A.m[0][2] = 1;
A.m[1][0] = 1;A.m[1][1] = 2;A.m[1][2] = 2;
A.m[2][0] = 0;A.m[2][1] = 0;A.m[2][2] = 1;
int n;
while (cin >> n) {
if (n == 1) {
cout << 1 << endl;
continue;
}
mat B = fast_pow(A, n-1);
//print(B);
cout << (B.m[0][0] + B.m[0][1]*2 + B.m[0][2])%Mod << endl;
}
return 0;
}