题目链接:Click me!
Chinese Rings
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1654 Accepted Submission(s): 951
Problem Description
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 Input
1
4
0
Sample Output
1
10
题意解析:
题上说,给出 N 个环套在棍子上,第一环可以直接取下或装上,但是一旦环的数量增加,要想取下或装上一个环(假设为第 k 个),则需要先取下前 k - 2 个环,然后装上第 k - 1 个,也就是取下第 k 个环的条件为:
- 前 k - 2 个必须都取下;
- 第 k - 1 个必须在棒子上;
题目要求是,给出 N 个环,要求我们计算出取下所有环需要得到最少操作数;
解题分析:
首先,我们计算出 1 ~ 5 个环时,所需要的最少操作数,也就是
环数 | 1 | 2 | 3 | 4 | 5 |
操作数 | 1 | 2 | 5 | 10 | 21 |
可以推出它的递推公式为:
这样的话,这个题是不是就要结束了呢?不是的,因为题上说,N <= 1,000,000,000,大概...是9个零吧,这么大的数,如果多次询问这么大的数,还要每次都计算九百万次,肯定会超时的吧;或者说,你想打表?这么大,你要把数组开十亿,空间也超了吧;所以说,不能用普通的计算方法啦,这里就到了矩阵快速幂的思想啦,我也是今天才刚刚学会(偷笑...)
思路就是,既然有跟、之间的关系,就可以把它们放入矩阵中,具体就是这么一个效果:
也就是我们需要的数据,那我们怎么处理,才能够求出呢?我们需要让下一个矩阵,乘出来以后,是这样的:
所以说,我们就需要自己去凑了,其实也不难,就直接按矩阵相乘,求出如何变化相乘,可以从上面那个矩阵求出下面的矩阵吧,也可以说是个简单的线性代数的题目,直接把数据代换一下,就可以解出来啦:
也就是这么个小题,解出来一个 3 * 3 的矩阵,就是我们要求的 X 啦,结果如下:
所以呢?我们需要把初始矩阵给设置成:
所以说,我们需要求 X 这个矩阵的 n - 1 次方,然后乘以我们的初始矩阵,结果就是 ans 矩阵的左上角的元素啦,也就是的结果啦!!
代码篇:
#include <iostream>
#include <cstring>
#define mod 200907
#define ll long long ///定义long long,不然数据会超
using namespace std;
struct ride ///用结构体存矩阵
{
ll x[10][10];
} res, ans;
ride Ride(ride a, ride b) ///矩阵相乘
{
ride c;
memset(c.x, 0, sizeof(c.x));
for(ll i = 0; i < 3; i++) ///普通的相乘方法,记得取模哦
{
for(ll j = 0; j < 3; j++)
{
for(ll k = 0; k < 3; k++)
{
c.x[i][j] = (c.x[i][j] + a.x[i][k] * b.x[k][j]) % mod;
}
}
}
return c;
}
int main()
{
ll n;
while(cin >> n, n != 0)
{
memset(ans.x, 0, sizeof(ans.x)); ///清空数组
memset(res.x, 0, sizeof(res.x));
res.x[0][0] = res.x[0][1] = res.x[2][0] = res.x[2][2] = 1, res.x[1][0] = 2;///设置初始数据
ans.x[0][0] = ans.x[0][2] = 1;
n -= 1; ///因为我们要求n - 1次方
while(n) ///快速幂算法
{
if(n & 1)
ans = Ride(ans, res);
res = Ride(res, res);
n /= 2;
}
cout << ans.x[0][0] % mod << endl;
}
return 0;
}
OVER!