这题一开始···我找出构造矩阵了,但是由于对费马小定理不太熟悉,所以并没有做出来,学习后,记录一下。
题目给的
这道题是没有办法直接写出对应F[n]的矩阵的,原因是因为无法分解因式。
但是有一种乘法中是蕴含加法的,就是同底相乘,指数相加。观察如下:
很容易发现a与b 的指数就是一个斐波那契数列,那么我们很容易通过下面这个矩阵求出指数
但是求出指数之后,你还是会WA的。
因为
所以指数也是会炸ll的,那怎么解决呢?这时候就要用到费马小定理了
费马小定理:
当gcd(a,p)=1时,有
所以就有
于是问题就完美解决了
AC代码,尚可优化
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define up(i,a,n) for(int i=a;i<=n;i++)
#define down(i,a,n) for(int i=a;i>=n;i--)
const int maxn=2;
const int md=1e9+7;
const int md1=1e9+6;
ll n,x,y;
struct node
{
ll a[maxn][maxn];
friend node operator * (node a,node b)
{
node c;
memset(c.a,0,sizeof(c.a));
up(i,0,1)
up(j,0,1)
up(k,0,1)
c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j]%md1)%md1;
return c;
}
}unit;
void init()
{
unit.a[0][0]=1;
unit.a[0][1]=1;
unit.a[1][0]=1;
unit.a[1][1]=0;
}
node pow_node(ll k)
{
node ans,a;
a=unit;
memset(ans.a,0,sizeof(ans.a));
up(i,0,1)
ans.a[i][i]=1;
while(k)
{
if(k&1)ans=ans*a;
k/=2;
a=a*a;
}
return ans;
}
ll pow_num(ll a,ll k)
{
ll ans=1;
a%=md;
while(k)
{
if(k&1)ans=((ans%md)*(a%md))%md;
k/=2;
a=((a%md)*(a%md))%md;
}
return ans;
}
int main()
{
while(~scanf("%lld %lld %lld",&x,&y,&n))
{ init();
x%=md,y%=md;
if(n==0)
{
printf("%lld\n",x%md);
continue;
}
if(n==1)
{
printf("%lld\n",y%md);
continue;
}
if(n==2)
{
printf("%lld\n",x*y%md);
continue;
}
if(n==3)
{
printf("%lld\n",x*y*y%md);
continue;
}
node s=pow_node(n-3);
ll ansa=0,ansb=0;
ansa=(ansa+s.a[0][0]*1%md1)%md1;
ansa=(ansa+s.a[0][1]*1%md1)%md1;
ansb=(ansb+s.a[0][0]*2%md1)%md1;
ansb=(ansb+s.a[0][1]*1%md1)%md1;
ll tansa,tansb;
tansa=pow_num(x,ansa);
tansb=pow_num(y,ansb);
printf("ansa=%lld ansb=%lld\n",ansa,ansb);
ll ttans=(tansa*tansb)%md;
printf("%lld\n",ttans);
}
}