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

来源:互联网 发布:二叉树的深度算法 编辑:程序博客网 时间:2024/04/30 07:47

题意:
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 longLL 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;    }}
0 0