HDU2842-Chinese Rings(递推+矩阵快速幂)

题目链接


题意:求出最少步骤解出九连环。取出第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;
}


你可能感兴趣的:(HDU2842-Chinese Rings(递推+矩阵快速幂))