题意:求出最少步骤解出九连环。取出第k个的条件是,k-2个已被取出,k-1个仍在支架上。
思路:想必九连环都玩过吧,其实最少步骤就是从最后一个环开始,向前一直取出来就行了。所以假设取出前n个环所需要的步骤为f(n),那么在此之前f(n - 2)要被取出,再加上1,即第n个环被取出,所以只剩下第n-1环没被取出,那么我们将前n-2环再套上去(套上去和取下来的步骤是一样,都为f(n - 2)),所以取出n-1环的步骤为f(n - 1),因此可以得到一个递推公式:f(n)
= f(n - 2) + 1 + f(n - 2) + f(n - 1) = f(n - 1) + 2f(n - 2) + 1;
因为n偏大,所以使用矩阵快速幂进行运算就可以了。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; //typedef long long ll; typedef __int64 ll; const int MOD = 200907; struct mat { ll s[3][3]; mat () { memset(s, 0, sizeof(s)); } mat operator * (const mat& c) { mat ans; memset(ans.s, 0, sizeof(ans.s)); for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++) for (int k = 0; k < 3; k++) ans.s[i][j] = (ans.s[i][j] + s[i][k] * c.s[k][j]) % MOD; return ans; } }tmp, c; ll n; void init() { tmp.s[0][0] = tmp.s[0][2] = tmp.s[1][0] = tmp.s[2][2] = c.s[1][0] = c.s[2][0] = 1; tmp.s[0][1] = c.s[0][0] = 2; } mat pow_mod(ll k) { if (k == 1) return tmp; mat a = pow_mod(k / 2); mat ans = a * a; if (k % 2) ans = ans * tmp; return ans; } int main() { init(); while (scanf("%I64d", &n) && n) { if (n == 1 || n == 2) { printf("%I64d\n", n); continue; } mat ans = pow_mod(n - 2); ans = ans * c; printf("%I64d\n", ans.s[0][0]); } return 0; }
时间: 2024-10-10 15:44:10