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;
}


posted @ 2016-03-16 18:17  phlsheji  阅读(172)  评论(0编辑  收藏  举报