
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5667
题意:如题给了一个函数式,给你a,b,c,n,p的值,叫你求f(n)%p的值
思路:先对函数取以a为底的log,令g(n)=log(a)(f(n)),结果就能得到
g(n)=b+c*g(n-1)+g(n-2);(n>3)
g(n)=0;(n=1)
g(n)=b;(n=2)
g(n) c 1 1 g(n-1)
用矩阵表示出来就是 g(n-1) = 1 0 0 * g(n-2)
b 0 0 1 b
设中间的矩阵为A 那么要求g(n)就是用A^(n-2)*g(2)来求得
g(1)
b
而我们要求的是 f(n)%p,f(n)=a^g(n),很明显g(n)是会爆的,那么因为p是质数,所以f(n)%p=(a^(g(n)%(p-1))%p
用快速幂一样的思路来模拟矩阵的乘法就行了
矩阵的乘法三个for循环就能写掉
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++)
tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j]);
然后设置三个矩阵,一个初始化为单位矩阵用来存储答案,一个存储当前的值,一个用来计算。
之后求出了g(n)的值之后,对原式还是要做一次快速幂,注意特判a%p==0的情况,0^0=1不处理
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#include <math.h>
using namespace std;
long long x[][];
long long y[][];
long long t;
long long n,a,b,c,p;
long long qpow1(long long a1,long long n1 )
{
long long ans=;
while(n1)
{
if(n1&)
ans=ans*a1%p;
a1=a1*a1%p;
n1>>=;
}
return ans;
}
void qpow(long long n1)
{
long long tmp[][];
memset(x,,sizeof(x));
for(int i=;i<;i++)
x[i][i]=; while(n1)
{
memset(tmp,,sizeof(tmp));
if(n1&)
{
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
for(int k=;k<;k++)
{
tmp[i][j]=(tmp[i][j]+x[i][k]*y[k][j]) % (p-);
}
}
}
for(int i=;i<;i++)
for(int j=;j<;j++)
x[i][j]=tmp[i][j];
}
memset(tmp,,sizeof(tmp));
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
for(int k=;k<;k++)
{
tmp[i][j]=(tmp[i][j]+y[i][k]*y[k][j]) % (p-);
}
}
}
for(int i=;i<;i++)
for(int j=;j<;j++)
y[i][j]=tmp[i][j];
n1>>=;
}
}
int main()
{
scanf("%lld",&t);
while(t--)
{
scanf("%lld %lld %lld %lld %lld",&n,&a,&b,&c,&p);
if(a%p==)
{
printf("0\n");
continue;
}
memset(y,,sizeof(y));
y[][]=c,y[][]=,y[][]=;
y[][]=,y[][]=,y[][]=;
y[][]=,y[][]=,y[][]=;
qpow(n-);
long long ans1=(x[][]*b+b*x[][])%(p-);
printf("%lld\n",qpow1(a,ans1));
}
return ;
}