传送门:http://acm.hdu.edu.cn/showproblem.php?pid=4291
A Short problem
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2845 Accepted Submission(s): 995
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 <= 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
Hence they prefer problems short, too. Here is a short one:
Given n (1 <= n <= 10 18), You should solve for
where
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).
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
Source
题解: 当看到公式的时候就知道要用矩阵快速幂,这就是它的功能。然而出现了个连环套的函数,一开始就将它分解了
内层函数看做外层函数的自变量,一开始是这么想的,在求快速幂的时候,自变量就是矩阵的指数,但是由内层
函数得出的数非常大,假设为k,那么g(k)就是求矩阵的(k-1)次方了然后模MOD,
因为有欧拉定理或者费马小定理知道对于一个数a^k%p=a^(k%oula(p))%p,然后我对矩阵快速幂也这么用了。但是wa,
从感性上能觉出这样取模的话会不精确容易出现票偏差,但是不知道怎么证明,,囧!
正确的方法是找每个mod的循环节,这样是没有任何偏差的了。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const LL mod1=1000000007;//求结果的循环节
const LL mod2=222222224;//第1层的循环节,假设g(g(g(n)))=g(x),即mod2是x的循环节
const LL mod3=183120;//第2层的循环节假设g(g(g(n)))=g(g(y)),即mod3是y的循化节
LL MOD;
struct mat{
LL a[2][2];
mat(){
memset(a,0,sizeof(a));
}
}e,ans;
mat mul(mat p1,mat p2)
{
mat t;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
t.a[i][k]+=p1.a[i][j]*p2.a[j][k];
t.a[i][k]%=MOD;
}
}
}
return t;
}
mat mi(mat p,LL k)
{
mat t;
for(int i=0;i<2;i++)t.a[i][i]=1;
while(k)
{
if(k&1)t=mul(t,p);
k=k>>1;
p=mul(p,p);
}
return t;
}
int main()
{
/*long long x3, x1=0,x2=1;
long long temp=1e9+7;
for(long long i=2;;i++)
{
x3=(3*x2+x1)%temp;
if(x3==1&&x2==0)
{
printf("%I64d\n",i-1);
break;
}
x1=x2;
x2=x3;
}*/
LL n;
while(~scanf("%lld",&n))
{
if(n==0||n==1)
{
printf("%lld\n",n);
continue;
}
e.a[0][0]=3;
e.a[0][1]=1;
e.a[1][0]=1;
e.a[1][1]=0;
MOD=mod3;
ans=mi(e,n-1);
MOD=mod2;
if(ans.a[0][0]>=2)ans=mi(e,ans.a[0][0]-1);
MOD=mod1;
if(ans.a[0][0]>=2)ans=mi(e,ans.a[0][0]-1);
printf("%lld\n",ans.a[0][0]);
}
return 0;
}