HDU 2842 Chinese Rings ( 矩阵转换,矩阵快速幂求解)

  • 题目链接: HDU 2842

  • 题意:

     有一种中国结,由n个环组成,问将n个环全部拆下来所需要的最小步数

    • 拆解条件:
      • 拆解第n个环,需要保证前n-2个环全部拆解下来,而第n-1个环保留(依旧悬挂)
  • 解法:

    设F[n]为拆解n个环所需要的最小步数.
    拆解n个环的情况下,在拆解第n个环时,需要先将前n-2个环拆解,需要F[n-2] + 1步(此1步为拆解第n个环的那一步),此时只剩下第n-1个环, 这个时候,要拆解第n-1个环,必须保证前n-3个环拆除完毕,且第n-2个环悬挂上去,所以需要将已拆解下来的前n-2个再次悬挂回去,需要F[n-2]步, 此时悬挂有n-1个环,题目变成为求解拆解n-1个环所需要的步数. 需F[n-1]步
    故 F[n] = F[n-2]+1+F[n-2]+F[n-1], 即 F[n] = F[n-1] + 2F[n-2] + 1
    F[n] = F[n-1] + 2F[n-2] + 1
    F[n+1] = F[n] + 2F[n-1] + 1
    构造矩阵 :
    | 1 2 1 |     | F[n-1] |      |  F[n] |
    | 1 0 0 |  * | F[n-2] | =   | F[n-1] |
    | 0 0 1 |     |     1     | =  |    1    |
    然后矩阵快速幂求解上述方程

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a; i<=b; ++i)
#define repp(i,a,b) for(int i=b; i>=a; --i)
#define mp make_pair
#define pb push_back
#define ms(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int>vi;
const ll mod = 200907;
const int maxn = 3;
ll mt[maxn][maxn] = {
    {1, 2, 1},
    {1, 0, 0},
    {0, 0, 1},
};
ll a, b;
struct Matrix{
    ll met[maxn][maxn];
    void init(bool status){
        if(status){
            rep(i, 0, maxn-1){
                rep(j, 0, maxn-1){
                    met[i][j] = mt[i][j];
                }
            }   
        } else {
            ms(met, 0);
            met[0][0]= 2;
            met[1][0] = 1;
            met[2][0] = 1;
        }   
    }
    Matrix operator * (Matrix t)
    {
        Matrix res;
        rep(i, 0, maxn-1){
            rep(j, 0, maxn-1){
                res.met[i][j] = 0;
                rep(k, 0, maxn-1)
                    res.met[i][j] = (res.met[i][j] + (met[i][k] % mod) * (t.met[k][j] % mod) % mod) % mod;
            }
        }
        return res;
    }
    Matrix operator ^ (ll k)
    {
        Matrix res,s;
        res.init(true);
        s.init(true);
        while(k){
            if(k & 1) res = res * s;
            k >>= 1;
            s = s * s;
        }
        return res;
    }
}tmp;
Matrix c;
int main(){
//  freopen("in.txt", "r", stdin);
    ll n;
    while(scanf("%lld",&n), n){
        if(n==1) printf("%lld\n", 1);
        else if(n==2) printf("%lld\n", 2);
        else {
            c.init(false);
            tmp.init(true);
            c=(tmp^(n-3))*c;
            printf("%lld\n", c.met[0][0]);  
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值