jiulianhuan 快速幂--矩阵快速幂

题目信息:

1471: Jiulianhuan

时间限制: 1 Sec   内存限制: 128 MB
提交: 95   解决: 22

题目描述

  For each data set in the input print on a separate line, on the standa  I think that you might have played the traditional Chinese ring game: The Chinese Linking Rings (here we call its nickname Jiulianhuan —— “九连环”). Well, you say you haven’t played it before? Then you must have seen it before, right? If not seen, come to borrow mine to have a good look at it and enjoy it!d output, the integer that represents the maximal amount of overtaking.


Now, I would like to mention the rules or common sense of Jiulianhuan again.
1) The first ring can put on or down the handles at any time. That is, when the first ring is under the handle, it can climb up the handle within one step, and vice versa.
2) At any moment, you can only operate one ring, on the condition that the ring is operable.
3) If the first k-2 rings are under the handle, and the (k-1)th ring is on the handle, then if the k-th ring is under the handle, you can put it on the handle, and if it is not under the handle, you can put it down the handle.
Seems complicated? But I tried my simplest explanation to you, and I hope its not hard for you to understand. Maybe you have played the game before,  and the above is what actually a “step” means in the game. 

输入

  Given n (not bigger than 10^8), you are to output the minimum steps it needs to down n well-put rings. There are no more than 100 test cases.

输出

  A number a line. Because the number are so huge ,you are to output the result after it mod prime 10007.

样例输入

1
2
9
1005

样例输出

1
2
341
4260

提示


/*
由题意可推知:
a(1)=1;
a(2)=2;
a(3)=5;
a(4)=10;
a(n) = a(n-1)+2*a(n-2)+1;
求得通项公式:
    a(1) = 1;
    a(2) = 2;
    奇数:a(n) = a1+3/4*(2^(n-1)-1);
    偶数:a(n) = a2+3/8*(2^(n-2)-1);

*/

三种方法实现该题:

/*********************************************************************/

//直接用通项公式求答案
#include "stdio.h"
#include "string.h"
#define MOD 10007
#define MOD_D 30021

int mypow(int a,int n)  //快速幂
{
    int y;
    if(n==0)
        return 1;
    y = mypow(a,n/2);
    y = (y*y)%MOD_D;
    if(n%2==1)
        y *= a;
    return y%MOD_D;
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==1) { printf("1\n"); continue; }
        if(n==2) { printf("2\n"); continue; }
        if(n%2==1)
            printf("%d\n",(1+(4*((mypow(2,n-1)-1)%MOD_D)/3)%MOD)%MOD);
        else
            printf("%d\n",(2+(8*((mypow(2,n-2)-1)%MOD_D)/3)%MOD)%MOD);
    }
    return 0;
}

/***********************************************************************/
//找循环节
#include "stdio.h"
#include "string.h"

#define N 1000007
#define MOD 10007
int p[N] = {0,1,2,5};

int main()
{
    int n;
    for(n=4; n<=N; ++n)
    {
        p[n] = (p[n-1] + 2*p[n-2] + 1)%MOD;
        if(p[n]==p[2] && p[n-1]==p[1])
            break;
    }
    int k = n-2;
    while(scanf("%d",&n)!=EOF)
    {
        n = (n-1)%k+1;
        printf("%d\n",p[n]);
    }
    return 0;
}

/******************************************************************/
//矩阵快速幂算法
#include "stdio.h"
#include "string.h"
#define MOD 10007

struct Matrix
{
    int n,m;
    int a[3][3];
}p0;

Matrix Mult_mod(Matrix a,Matrix b)
{
    Matrix c;
    c.n = a.n;
    c.m = b.m;
    int i,j,k;
    for(i=0; i<a.n; ++i)
    {
        for(j=0; j<a.m; ++j)
        {
            c.a[i][j] = 0;
            for(k=0; k<a.m; ++k)
                c.a[i][j] += (a.a[i][k]*b.a[k][j])%MOD;
        }
    }
    return c;
}

Matrix power_mod(Matrix a,int n)
{
    if(n==1)
        return p0;
    Matrix y = power_mod(a,n/2);
    y = Mult_mod(y,y);
    if(n%2==1)
        y = Mult_mod(y,p0);
    return y;
}

int main()
{
    int n;
    memset(p0.a,0,sizeof(p0.a));
    p0.n = 3;
    p0.m = 3;
    p0.a[0][0] = 1;
    p0.a[0][1] = 1;
    p0.a[1][0] = 2;
    p0.a[2][0] = 1;
    p0.a[2][2] = 1;
    Matrix ans;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==1) printf("1\n");
        else if(n==2) printf("2\n");
        else
        {
            ans = power_mod(p0,n-2);
            printf("%d\n",(2*ans.a[0][0]+ans.a[1][0]+ans.a[2][0])%MOD);
        }

    }
    return 0;
}













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值