您的位置:首页 > 其它

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

2015-08-26 11:21 435 查看
[align=left]Problem Description[/align]
  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

[align=left]Input[/align]
  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).

[align=left]Output[/align]
  For each test case, please print a single line with a integer, the corresponding answer to this case.

[align=left]Sample Input[/align]

0
1
2

[align=left]Sample Output[/align]

0
1
42837

这题主要找循环节,mo1=1000000007,mo2=222222224,mo3=183120;找到循环节后只要用矩阵快速幂就可以了,下面有找循环节代码。
由于找循环节很耗时,所以找到后直接写出来,不用写在代码里。

找循环节:

#include<cstdio>
long long mo1=1000000007;
int main()
{
long long i=1,a=1,b=0,c;
while (i)
{
c=(3*a+b)%mo1;
b=a;
a=c;
if (a==1&&b==0)
{
printf("%I64d\n",i);
break;
}
i++;
}
}


View Code

ac代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
long long mo1=1000000007;
long long mo2=222222224;
long long mo3=183120;
long long s1[3][3],s2[3][3],s3[3][3];
long long f(long long n,long long mo)
{
int i,j,k;
s1[0][0]=s2[0][0]=3;
s1[0][1]=s2[0][1]=1;
s1[1][0]=s2[1][0]=1;
s1[1][1]=s2[1][1]=0;
n-=2;
while (n)
{
if (n&1)
{
memset(s3,0,sizeof(s3));
for (k=0;k<2;k++)
for (i=0;i<2;i++){if (!s1[i][k]) continue;
for (j=0;j<2;j++)
s3[i][j]=(s3[i][j]+s1[i][k]*s2[k][j])%mo;}
for (i=0;i<2;i++)
for (j=0;j<2;j++) s2[i][j]=s3[i][j];
}
memset(s3,0,sizeof(s3));
for (k=0;k<2;k++)
for (i=0;i<2;i++) {if (!s1[i][k]) continue;
for (j=0;j<2;j++)
s3[i][j]=(s3[i][j]+s1[i][k]*s1[k][j])%mo;}
for (i=0;i<2;i++)
for (j=0;j<2;j++) s1[i][j]=s3[i][j];
n>>=1;
}
return s2[0][0];
}
int main()
{
long long n;
long long ans;
while (~scanf("%I64d",&n))
{
if (n==0) {printf("0\n");continue;}
if (n==1) {printf("1\n");continue;}
ans=f(n,mo3);
if (ans>=2) //一定要有,不然ans<2时函数就会死循环。
ans=f(ans,mo2);
if (ans>=2)
ans=f(ans,mo1);
printf("%I64d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: