HDU 4291 A Short problem (矩阵快速幂+循环节)

  According to a research, VIM users tend to have shorter fingers, compared with Emacs users.
  Hence they prefer problems short, too. Here is a short one:
  Given n (1 <= n <= 10 18), You should solve for

                                                                 g(g(g(n))) mod 10 9 + 7

        where

                                                                 g(n) = 3g(n - 1) + g(n - 2)

                                                                 g(1) = 1  g(0) = 0

 

Input

  There are several test cases. For each test case there is an integer n in a single line.
  Please process until EOF (End Of File).

Output

  For each test case, please print a single line with a integer, the corresponding answer to this case.

Sample Input

0
1
2

Sample Output

0
1
42837

从最外层找循环节

最外层:即当mod为1000000007时

暴力找出循环节为2222222224

即g(222222225%222222224)%1000000007=g(1)%1000000007;

即g(x)%1000000007=g(x%222222224)%1000000007;

第二层:即当mod为222222224时

暴力找出循环节为183120

即g(183121%183120)%222222224=g(1)%222222224;

即g(x)%222222224=g(x%183120)%222222224;

第三层:即当mod为183120时

暴力找出循环节为240;

即g(241%240)%183120=g(1)%183120;

即g(x)%183120=g(x%240)%183120;

最后:g(g(g(n)))%1000000007=g(g(g(n)%222222224)%1000000007=g(g(g(n)%183120)%222222224)%1000000007

=g(g(g(n%240)%183120)%222222224)%1000000007;

暴力跑循环节代码:

#include <bits/stdc++.h>

using namespace std;

long long get(long long mod)
{
    long long u=1,v=3;
    long long ans;
    for(int i=1;i<=999999999;i++)
    {
        if(u==0&&v==1)
        {
            ans=i;
            break;
        }
        long long t=u;
        u=v;
        v=(t+3*v)%mod;
    }
    return ans;
}

int main()
{
    int mod;
    while(cin >> mod)
    {
        cout << get(mod) << endl;
    }
    return 0;
}

AC代码:

#include <bits/stdc++.h>

using namespace std;

struct node{
    long long a[2][2];
}ans,k,t;

long long mod1=183120;
long long mod2=222222224;
long long mod3=1000000007;

node mult(node x,node y,long long mod)
{
    node now;
    now.a[0][0]=(x.a[0][0]*y.a[0][0]%mod+x.a[0][1]*y.a[1][0]%mod)%mod;
    now.a[0][1]=(x.a[0][0]*y.a[0][1]%mod+x.a[0][1]*y.a[1][1]%mod)%mod;
    now.a[1][0]=(x.a[1][0]*y.a[0][0]%mod+x.a[1][1]*y.a[1][0]%mod)%mod;
    now.a[1][1]=(x.a[1][0]*y.a[0][1]%mod+x.a[1][1]*y.a[1][1]%mod)%mod;
    return now;
}

long long quick_pow(long long n,long long mod)
{
    n--;
    ans.a[0][0]=1;
    ans.a[1][1]=1;
    ans.a[0][1]=0;
    ans.a[1][0]=0;
    k=t;
    while(n)
    {
        if(n&1)
        {
            ans=mult(ans,k,mod);
        }
        k=mult(k,k,mod);
        n>>=1;
    }
    return ans.a[0][0]%mod;
}

int main()
{
    long long n;
    t.a[0][0]=3;
    t.a[0][1]=1;
    t.a[1][0]=1;
    t.a[1][1]=0;
    while(cin >> n)
    {
        n%=240;
        if(!n)
        {
            cout << 0 << endl;
            continue;
        }
        n=quick_pow(n,mod1);
        n=quick_pow(n,mod2);
        n=quick_pow(n,mod3);
        cout << n << endl;
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值