题目链接: 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;
}