Dumbear likes to play the Chinese Rings (Baguenaudier). It’s a game played with nine rings on a bar. The rules of this game are very simple: At first, the nine rings are all on the bar.
The first ring can be taken off or taken on with one step.
If the first k rings are all off and the (k + 1)th ring is on, then the (k + 2)th ring can be taken off or taken on with one step. (0 ≤ k ≤ 7)
Now consider a game with N (N ≤ 1,000,000,000) rings on a bar, Dumbear wants to make all the rings off the bar with least steps. But Dumbear is very dumb, so he wants you to help him.
Input
Each line of the input file contains a number N indicates the number of the rings on the bar. The last line of the input file contains a number "0".
Output
For each line, output an integer S indicates the least steps. For the integers may be very large, output S mod 200907.
Sample
Inputcopy | Outputcopy |
---|---|
1 4 0 | 1 10 |
题目大意:
初始所有n个环都放上
只能做两种操作
1:把第1个取下或者放上
2:如果前k个都取下(k>=0),第k+1个未取下,那么就可以选择取下或放上第k+2个
问:把n个环都取下的最小操作次数
解题思路:
由于n范围特别大,所以用矩阵快速幂来求解
首先很容易得到F(1)=1,F(2)=2
(下面以√代表未取下,×代表取下)
当n=3的时候:
发现第3个环若要取下
一定只能使用第二种操作,也就是此时第1个取下,第2个未取下,才能取下第3个
然后复原第1个,此时变成了√√x,也就是需要F(2)次操作就行
当n=4的时候:
发现第4个环若要取下
一定只能使用第二种操作,也就是此时第1,2个取下,第3个未取下,才能取下第4个
然后复原第1,2个,此时变成了√√√x,也就是需要F(3)次操作就行
当n=6的时候:(如图)
同理,首先取下第1,2,3,4个也就是(+F(n-2)),然后取下第6个(+1),然后复原第1,2,3,4个(+F(n-2)),最后再操作F(n-1)次(+F(n-1));
得出结论:F(n)=2*F(n-2)+F(n-1)+1
为了求出转移矩阵,先列一个表
n 1 2 3 4 5 6 ...
F(n) 1 2 5 10 21 42 ...
首先由于F(n)与前面两项都有关,所以行矩阵长度取3,递推矩阵C设为
[
[a1,b1,c1]
[a2,b2,c2]
[a3,b3,c3]
]
由于每一列有三个未知数,我们只需要列出三个方程就可以解出来所有的未知数
①[1,2,5]*C=[2,5,10]
②[2,5,10]*C=[5,10,21]
③[5,10,21]*C=[10,21,42](为了计算方便也可以写[0,1,2]*C=[1,2,5],因为0,1,2也满足递推的规律)
①②③联立可解出
递推矩阵:C=[[1,1,0],[2,0,0],[1,0,1]]
于是本题得解
代码实现:
#include <map>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define int long long
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
int n;
const int N=3;
const int P=200907;
void mul(int c[],int f[],int cheng[][N])//行向量×矩阵
{
int cun[N]={0};
for(int j=0;j<N;j++)
{
for(int k=0;k<N;k++)
{
cun[j]=(cun[j]+f[k]*cheng[k][j])%P;
}
}
memcpy(c,cun,sizeof(cun));
}
void mul(int c[][N],int f[][N],int cheng[][N])
{
int cun[N][N]={0};
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
for(int k=0;k<N;k++)
{
cun[i][j]=(cun[i][j]+f[i][k]*cheng[k][j])%P;
}
}
}
memcpy(c,cun,sizeof(cun));
}
signed main()
{
IOS;
while(cin>>n,n)
{
int res[N]={0,1,2},cheng[N][N]={{1,1,0},{2,0,0},{1,0,1}};
while(n)
{
if(n&1)mul(res,res,cheng);
mul(cheng,cheng,cheng);
n>>=1;
}
cout<<res[0]<<endl;
}
}