[矩阵快速幂+循环节]hdu4291

题意:

Given n (1 <= n <= 1018), You should solve for

g(g(g(n))) mod 109 + 7

  where

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

g(1) = 1

g(0) = 0

分析:

这个递推关系可以用矩阵快速幂来解决,但是这个题的问题是mod很大,会爆long long 并且超时的。那么这就需要一些特技了。

于是看到大家都用的循环节,但是网上对为什么要这么取循环节却都模糊或者答非所问,大概都不太晓得,知道可以A提就可以了,或者是大神们觉得这些小儿科的东西不用提上来讲。我的理解是这是一个自变量与函数值之间的关系的一种利用吧,比如g(x)%mod, 随着g(x)的增大,总有一天会大过mod,然后又被变成0,重新开始,所以g(x)是循环的,它的循环节是mod,那么g(x)的变化是随着x的变化而变化的,那么g(x)循环,x 也会相应的有循环节(这是根据函数的性质来决定的,不是所有的函数都有循环节,起码这种类似斐波那契数列的函数可以),也就是说当x到达一个值n时,g(x)==mod,x大于n之后g(x)也大过mod,那么n+1和之前的1效果是一样的,所以x的循环节就是n. 在这个题中有多个循环节是因为函数的嵌套,那么最外层求得的自变量的循环节mod1就是里面嵌套函数的函数值的循环节,依次递推,找到三个循环节。

#include <iostream>
#include <cstdio>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
using namespace std;
#define read freopen("q.in","r",stdin)
#define LL long long

LL mod ;
struct Matri
{
    LL mat[2][2];
    //Matri(){memset(mat,0,sizeof(mat));}
    void init()
    {
        mat[0][1]=mat[1][0]=0;
        mat[0][0]=mat[1][1]=1;
    }
};

Matri mul(Matri a,Matri b)
{
    Matri res;
    int i,j,k;
    for(i=0;i<2;i++)
    {
        for(j=0;j<2;j++)
        {
            res.mat[i][j]=0;
            for(k=0;k<2;k++)
            {
                res.mat[i][j]=(res.mat[i][j]+(a.mat[i][k]*b.mat[k][j])%mod)%mod;
            }
        }
    }
    return res;
}

Matri exp(Matri a,LL n)
{
    Matri res;
    res.init();
    if(n==0)return res;
    if(n==1)return a;
    while(n)
    {
        if(n&1)res=mul(res,a);

        a=mul(a,a);
        n>>=1;
    }
    return res;
}

int main()
{
    Matri B;B.mat[0][0]=3;B.mat[0][1]=1;B.mat[1][0]=1;B.mat[1][1]=0;
    // circle();
    // cout<<mod<<"??£í£í£í£í£í??"<<endl;
    LL n;
    while(~scanf("%I64d",&n))
    {
        if(n==0)
        {
            puts("0");
            continue;
        }
        if(n==1)
        {
            puts("1");
            continue;
        }
        mod=183120L;

        Matri res=exp(B,n-1);
        n=res.mat[0][0];
        if(n!=0 && n!=1)
        {
            mod=222222224L;
            res=exp(B,n-1);
            n=res.mat[0][0];
        }
        if(n!=0 && n!=1)
        {
            mod=1000000007L;
            res=exp(B,n-1);
        }
        cout<<res.mat[0][0]<<endl;
    }

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-08 17:30:50

[矩阵快速幂+循环节]hdu4291的相关文章

hdu 4291(矩阵快速幂 + 循环节)

题意:求s s = g(g(g(n))) mod 1000000007 其中g(n) g(n) = 3g(n - 1) + g(n - 2) g(1) = 1 g(0) = 0 题解:普通的矩阵快速幂会超时,看到别人的题解是需要计算循环节得到小的MOD从而减小计算量.1000000007太大,需要计算更小的一个循环节,新技能get. #include <stdio.h> #include <string.h> struct Mat { long long g[3][3]; }ori

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

A Short problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2461    Accepted Submission(s): 864 Problem Description According to a research, VIM users tend to have shorter fingers, compared

【矩阵快速幂+循环节】HDU 5451 Best Solver

通道 题意:计算(5+26√)1+2^x. 思路:循环节是(p+1)*(p-1),然后就是裸的矩阵快速幂啦. 代码: #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N = 2; int MOD; struct

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

题目链接": http://acm.hdu.edu.cn/showproblem.php?pid=4291 题意: g(0)=0,g(1)=1; g(n) = 3g(n - 1) + g(n - 2): 求g(g(g(n))) mod 109 + 7 分析: 首先我们得认识到,如果一层一层算是必定会超时的. 其次,取模运算是有循环节的. step1我们找出g(x)%1000000007的循环节 mod1 step2 设g(g(n)) = g(x) x=g(n) 对mod1 取模得到mod2. 剩

acdream 1060 递推数 (矩阵快速幂+循环节)

链接:click here~~ 题意: 递推数 Problem Description 已知A(0) = 0 , A(1) = 1 , A(n) = 3 * A(n-1) + A(n-2) (n ≥ 2)    求 A(A(A(A(N)))) Mod (1e9 + 7) Input 第一行一个整数 T (T ≤ 10000) 代表数据组数 每组数据占一行,一个整数 n (1 ≤ n ≤ 1e12) Output 对于每组测试数据输出一个整数. Sample Input 4 1 23574 278

hdu 5451 Best Solver(矩阵快速幂+循环节)

题意: 已知,给你整数x,和一个素数M,求[y]%M 思路: 设 (5+2√6)n=Xn+Yn*√6 Xn+Yn*√6 =(Xn-1+Yn-1*√6)*(5+2√6) => 5*Xn-1 + 12*Yn-1 + (2*Xn-1 + 5*Yn-1 )*√6 Xn =  5*Xn-1 + 12*Yn-1: Yn =  2*Xn-1 + 5*Yn-1: 然而√6还是一个大问题,解决办法: (5 - 2√6)n = Xn - Yn*√6 (5+2√6)n=Xn+Yn*√6 + Xn - Yn*√6 -

HDU 4291 A Short problem (2012成都网络赛,矩阵快速幂+循环节)

链接: click here~~ 题意: 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 <= 1018), You should solve for g(g(g(n))) mod 109 + 7 where

HDU 5690——All X——————【快速幂 | 循环节】

All X Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 879    Accepted Submission(s): 421 Problem Description F(x,m) 代表一个全是由数字x组成的m位数字.请计算,以下式子是否成立: F(x,m) mod k ≡ c Input 第一行一个整数T,表示T组数据.每组测试数据占

hdu 4291 矩阵幂 循环节

http://acm.hdu.edu.cn/showproblem.php?pid=4291 凡是取模的都有循环节-----常数有,矩阵也有,而且矩阵的更神奇: g(g(g(n))) mod 109 + 7  最外层MOD=1e9+7  可以算出g(g(n))的循环节222222224,进而算出g(n)的循环节183120LL,然后由内而外计算即可 注释掉的是求循环节的代码 //#pragma comment(linker, "/STACK:102400000,102400000")