题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4291
题意:g(0)=0,g(1)=1,g(n)=3g(n-1)+g(n-2),mod=1000000007。求g(g(g(n)))%mod。
思路:设g(0)=a,g(1)=b,g(n)=c*g(n-1)+d*g(n-2)。构造矩阵A,B(均为2*2的矩阵)A={a,b,0,0},B={c,1,d,0}。则g(n)等于(A*(B^(n-1)))的第一个元素。对于本题,设mod的循环节是L1,L1的循环节是L2,则答案为g(g(g(n)%L2)%L1)%mod。。那么循环节是什么东西呢?
#include <iostream>
using namespace std;
const __int64 MOD=1000000007;
int main()
{
__int64 f0=0,f1=1,temp,i;
for(i=1;;i++)
{
temp=(3*f1+f0)%MOD;
f0=f1;
f1=temp;
if(f0==0&&f1==1)
{
printf("%I64d\n",i);
break;
}
}
return 0;
}
对于ans=g(g(n))%mod,如果g(g(n)%mod)%mod这样显然是不对的。g(g(n)%L1)%mod才是正确的。为什么呢?因为对于本题的g(0)=0,g(1)=1来说,对于mod每L1次就会重新回来,所以你在计算的过程中用L1去模掉中间值跟最后模掉mod是一样的!!!
#include <iostream>
using namespace std;
const __int64 L1=1000000007;
const __int64 L2=222222224;
const __int64 L3=183120;
__int64 n;
struct node
{
__int64 m[2][2];
node()
{
memset(m,0,sizeof(m));
}
node(__int64 a,__int64 b,__int64 c,__int64 d)
{
m[0][0]=a;
m[0][1]=b;
m[1][0]=c;
m[1][1]=d;
}
node Mul(node b,__int64 mod)
{
int i,j,k;
node ans;
for(i=0;i<2;i++) for(j=0;j<2;j++) for(k=0;k<2;k++)
ans.m[i][j]=(ans.m[i][j]+m[i][k]*b.m[k][j])%mod;
return ans;
}
node Rep(__int64 p,__int64 mod)
{
node b=*this,ans(1,0,0,1);
if(p==0) return ans;
if(p==1) return b;
while(p>1)
{
if(p&1) ans=ans.Mul(b,mod);
b=b.Mul(b,mod);
p>>=1;
}
return b.Mul(ans,mod);
}
};
__int64 g(__int64 n,__int64 mod)
{
if(!n) return 0;
node p(3,1,1,0);
return p.Rep(n-1,mod).m[0][0];
}
int main()
{
while(scanf("%I64d",&n)!=-1) printf("%I64d\n",g(g(g(n,L3),L2),L1));
return 0;
}