题目描述
acndy喜欢做数学题,学了数论以后更是一发不可收拾,他发现一个数列:
给出n,a,b,c的值,他想算出fn模p后的值。
输入
第一行一个数T,为测试数据组数,
每组数据一行,一行五个正整数,按顺序为n,a,b,c,p,
1<=T<=10,1<=n<=1e18,1<=a,b,c<=1e9,p是质数且p<=1e9+7。
输出
对每组数据输出一行一个数,输出fn对p取模后的数值
提示
费马小定理: 假如p是质数,且gcd(a,p)=1,那么 a^(p-1)%p=1。
发现好久没有写博客了。
评价:额,算难题么?只要知道矩阵快速幂就会做了。偏简单题,但是要注意细节
易知
f(n)=ag(n)f(n)=ag(n)
g(n)=cg(n−1)+g(n−2)+bg(n)=cg(n−1)+g(n−2)+b
g(1)=0,g(2)=bg(1)=0,g(2)=b
显然是构成3乘3的矩阵。
⎡⎣⎢g(n)g(n−1)b⎤⎦⎥=⎡⎣⎢c10100101⎤⎦⎥∗⎡⎣⎢g(n−1)g(n−2)b⎤⎦⎥[g(n)g(n−1)b]=[c11100001]∗[g(n−1)g(n−2)b]
所以:
⎡⎣⎢g(n)g(n−1)b⎤⎦⎥=⎡⎣⎢c10100101⎤⎦⎥n−2∗⎡⎣⎢b0b⎤⎦⎥(n>2)[g(n)g(n−1)b]=[c11100001]n−2∗[b0b](n>2)
这样的话,就只要当作快速幂来做就好了,只不过重新定义一下乘法而已。
代码:
import java.util.Scanner;
public class Main
{
static long n,a,b,c,p;
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
//System.out.println(P(3,186));
int t=sc.nextInt();
while((t--)>0)
{
n=sc.nextLong();
a=sc.nextLong();
b=sc.nextLong();
c=sc.nextLong();
p=sc.nextLong();
a%=p;
if(a==1||n==1)
System.out.println(1);
else
if(a%p==0)
{
if(n==1)
System.out.println(1);
else
System.out.println(0);
}//按照得分,上面那些情况,数据是没有的,不写也无所谓了
else
{
if(n==2)
System.out.println(P(a,b));
else
{
M ans=M.unit();//单位矩阵
M A=new M();
A.a[0][0]=c;
A.a[0][1]=1;
A.a[0][2]=1;
A.a[1][0]=1;
A.a[2][2]=1;//设置系数
n-=2;
while(n>0)
{
if((n&1)==1)
ans=ans.mui(A, p-1);
A=A.mui(A,p-1);//这里要注意了,是对p-1取模,我就死在这了,想当然对p取模了
n>>=1;
}//纯粹模拟快速幂
long top=(b*ans.a[0][0]+b*ans.a[0][2])%(p-1);
//System.out.println(top);
System.out.println(P(a,top));
}
}
}
}
static long P(long x,long k)
{
long ans=1;
while(k>0)
{
if((k&1)==1)
ans=ans*x%p;
x=x*x%p;
k>>=1;
}
return ans;
}
}
class M
{
long a[][]=new long[3][3];
static M unit()
{
M m=new M();
m.a[0][0]=1;
m.a[1][1]=1;
m.a[2][2]=1;
return m;
}
M mui(M o,long mod)//定义乘法
{
M ans=new M();
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
{
ans.a[i][j]=0;
for(int k=0;k<3;k++)
ans.a[i][j]=(ans.a[i][j]+a[i][k]*o.a[k][j]%mod)%mod;
}
return ans;
}
}