直击题目:https://vjudge.net/problem/41990/origin
题目大意:
给出三个数,a,b,n;其中a,b<2^64;n<1000。已知Fibonacc的数的递推公式,f[0]=0,f[1]=1;f[i+2]=f[i+1]+f[i].然后求出f[a^b]对n取模的值。
题解:首先看到的是这个公式,f[i]=f[i-1]+f[i-2],那么假设f[a^b]=f[i]。而f[a^b]%n=f[i]%n=f[i-1]%n+f[i-2]%n.然后根据递推的关系可以看出,其实在求的过程中对每一个f[i]取模就可以了。当进行到这里的时候该怎么化简一下a^b呢?显然没有这么大的数组。这时可以考虑一下有没有规律周期可以寻找。通过打表,可以看出,其实对于每一个n,都有一个f[i]对n取余的循环周期,那么假设这个周期是g[n],表示以n模的Fibonacc周期。然后在回头看a^b,因为是有周期的,那么a^b对他的周期取余就可以了,这就涉及到了幂取模的分治法。然后就可以得出答案了。
注意:这个题要用cin才行,scanf会wa,真是wa的都无语了。当然还要注意边界,当n==1或a==0是,都是0;
还有一点就是,因为a很大,当进行幂取模前先对a取模一下
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
unsigned long long a,b;
int f[1050][65000];
int g[1055];
int pow_mod(unsigned long long a,unsigned long long b,int n)
{
if(b==0)return 1;
int x=pow_mod(a,b/2,n);
int ans=x*x%n;
if(b%2==1)ans=ans*a%n;
return ans;
}
int main()
{
for(int i=2; i<1010; i++)
{
f[i][0]=0;
f[i][1]=1;
for(int j=2;; j++)
{
f[i][j]=(f[i][j-1]+f[i][j-2])%i;
if(f[i][j]==1&&f[i][j-1]==0)
{
g[i]=j-1;
break;
}
}
}
int t,n;
cin>>t;
while(t--)
{
cin>>a>>b>>n;
if(n==1||a==0)
{
cout<<0<<endl;
}
else
{
int x=pow_mod(a%g[n],b,g[n]);
cout<<f[n][x]<<endl;
}
}
return 0;
}