HDU 2842 Chinese Rings(矩阵快速幂+递推矩阵的计算)

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

InputcopyOutputcopy
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;
	}
}
  • 33
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值