HDU 2842 - Chinese Rings(矩阵快速幂优化)

题目链接: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 个环的条件为:

  1. 前 k - 2 个必须都取下;
  2. 第 k - 1 个必须在棒子上;

题目要求是,给出 N 个环,要求我们计算出取下所有环需要得到最少操作数;

解题分析:

首先,我们计算出 1 ~ 5 个环时,所需要的最少操作数,也就是

环数12345
操作数1251021

可以推出它的递推公式为:

                                                                      F_{n}=F_{n-1}+2F_{n-2}+1

这样的话,这个题是不是就要结束了呢?不是的,因为题上说,N <= 1,000,000,000,大概...是9个零吧,这么大的数,如果多次询问这么大的数,还要每次都计算九百万次,肯定会超时的吧;或者说,你想打表?这么大,你要把数组开十亿,空间也超了吧;所以说,不能用普通的计算方法啦,这里就到了矩阵快速幂的思想啦,我也是今天才刚刚学会(偷笑...)

思路就是,既然有F_{n}F_{n-1}F_{n-2}之间的关系,就可以把它们放入矩阵中,具体就是这么一个效果:

也就是我们需要的数据,那我们怎么处理,才能够求出F_{n}呢?我们需要让下一个矩阵,乘出来以后,是这样的:

所以说,我们就需要自己去凑了,其实也不难,就直接按矩阵相乘,求出如何变化相乘,可以从上面那个矩阵求出下面的矩阵吧,也可以说是个简单的线性代数的题目,直接把数据代换一下,就可以解出来啦:

也就是这么个小题,解出来一个 3 * 3 的矩阵,就是我们要求的 X 啦,结果如下:

所以呢?我们需要把初始矩阵给设置成:

所以说,我们需要求 X 这个矩阵的 n - 1 次方,然后乘以我们的初始矩阵,结果就是 ans 矩阵的左上角的元素啦,也就是F_{n}的结果啦!!

代码篇:

#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!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值