HDU 4291解题报告

来源:互联网 发布:域名买卖网 编辑:程序博客网 时间:2024/05/17 20:22

A Short problem

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1838    Accepted Submission(s): 670


Problem Description
  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
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
012
 

Sample Output
0142837
 

Source
2012 ACM/ICPC Asia Regional Chengdu Online
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:  4296 4295 4294 4293 4292 

       这道题是比较裸的矩阵快速幂的题。但是与一般的题不一样的就是取模的是复合函数,而且是对最外层的取模,因此内部的数字可能会非常大。g(n)=3*g(n-1)+g(n-2)这个是标准的二阶线性递推式,我们可以类比斐波那契数列的公式。令Y=g(g(x)),mod=1000000007,则所求的转换成了g(Y)%mod的结果。这里出现了取模的符号。而本题的特点就在于数字会非常大。我们也知道二阶线性递推式取模必然会出现周期性的循环。因此我们可以暴力模拟得出g(Y)%mod的Y的周期,得到Y的周期为t1=222222224,即g(g(g(x)))%mod=g(g(g(x))-k*t1)%mod,所以计算时为了缩小范围我们只需计算g(g(x))%t1的值即可。即g(g(g(x)))%mod=g(g(g(x))%t1)%mod。要计算g(g(x))%t1,这样我们再次令Z=g(x),则此时所求结果为g(Z)%t1,这是可以得到Z的周期为t2=183120,即g(g(x))%t1=g(g(x)%t2)%t1。这样所求为g(x)%t2,我们再次暴力模拟,得到x的周期为t3=240。所以最终所求结果为g(g(g(x)))%mod=g(g(g(x%t3)%t2)%t1)%mod。这样通过层层取模我们便可以减小所得的数字的规模,防止数字过大导致的溢出问题。

       通过这道题的训练,我们发现该题的难点不在矩阵快速幂。因为我们很清楚的知道,当出现线性递推式时,而且在n特别大时就应该有矩阵快速幂降低复杂度的意识。而本题的复合函数是一个难点。而突破这个难点就要从取模周期上降低数字的规模。取模的周期性这些小的技巧在这种难题中我们一定要注意。往往容易被忽视的小技巧才是解决问题的关键之处。

       参考代码:

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#include<string>#include<vector>#include<map>#include<set>#include<stack>#include<queue>#include<ctime>#include<cstdlib>#include<iomanip>#include<utility>#define pb push_back#define mp make_pair#define CLR(x) memset(x,0,sizeof(x))#define _CLR(x) memset(x,-1,sizeof(x))#define REP(i,n) for(int i=0;i<n;i++)#define Debug(x) cout<<#x<<"="<<x<<" "<<endl#define REP(i,l,r) for(int i=l;i<=r;i++)#define rep(i,l,r) for(int i=l;i<r;i++)#define RREP(i,l,r) for(int i=l;i>=r;i--)#define rrep(i,l,r) for(int i=1;i>r;i--)#define read(x) scanf("%d",&x)#define put(x) printf("%d\n",x)#define ll long long#define lson l,m,rt<<1#define rson m+1,r,rt<<11using namespace std;int T1=222222224,T2=183120,T3=240,mod=1000000007;ll n;struct mat{    ll d[2][2];}A,B,E;mat multi(mat a,mat b,int mod){    mat ans;    rep(i,0,2)    {        rep(j,0,2)        {            ans.d[i][j]=0;            rep(k,0,2)            {                if(a.d[i][k]&&b.d[k][j])                    ans.d[i][j]=(ans.d[i][j]+a.d[i][k]*b.d[k][j])%mod;            }        }    }    return ans;}mat quickmulti(mat a,ll n,int mod){    mat ans=E;    while(n)    {        if(n&1)        {            n--;            ans=multi(ans,a,mod);        }        else        {            n>>=1;            a=multi(a,a,mod);        }    }    return ans;}int main(){   A.d[0][0]=3,A.d[0][1]=1,A.d[1][0]=1,A.d[1][1]=0;   B.d[0][0]=1,B.d[0][1]=0,B.d[1][0]=0,B.d[1][1]=0;   E.d[0][0]=1,E.d[0][1]=0,E.d[1][0]=0,E.d[1][1]=1;   while(~scanf("%I64d",&n))   {       n%=T3;       mat ans=quickmulti(A,n,T2);       ans=multi(ans,B,T2);       int shu=ans.d[1][0];       ans=quickmulti(A,shu,T1);       ans=multi(ans,B,T1);       shu=ans.d[1][0];       ans=quickmulti(A,shu,mod);       ans=multi(ans,B,mod);       printf("%I64d\n",ans.d[1][0]);   }}

0 0