题目
给定0<=a,b<,1<=n<=1000,
求fib()%n
思路来源
https://www.cnblogs.com/naturepengchen/articles/3947118.html
题解
注意到,n<=1000的时候,最多n²项会出现循环节,
实际循环节的证明见“斐波那契数列模n条件下循环节的长度”的证明
打表可以证明,n<=1000的情况下,循环节的长度,最大为3000
而且,加的循环节对减时%n同时成立,
所以,出现循环节后,不会出现一个ρ字形,而会是环
注意a==0的时候,如果不特判会输出1;
注意n==1的时候,直接特判
预处理3000*1000的表,
预处理循环节,询问时直接查表
心得
%llu输成%u,debug50min,我枯了
这种有确定的环的循环节,直接和第一二项比对
不然如果开vis[1005][1005]的数组,每次都清空实际是1e9的复杂度
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
typedef unsigned long long ull;
//const int maxn=1e6+10;
//const int maxm=1e3+10;
/*打表循环节
int vis[maxm][maxm];
int f[maxn];
void init(int n)
{
memset(vis,0,sizeof vis);
f[0]=0;f[1]=1;
int res=0;
for(int i=0;i<maxn-2;++i)
{
f[i+2]=(f[i+1]+f[i])%n;
if(vis[f[i]][f[i+1]])
{
res=max(res,i-vis[f[i]][f[i+1]]);
break;
}
else vis[f[i]][f[i+1]]=i;
}
printf("%d:%d\n",n,res);
}
void test()
{
for(int i=2;i<=1000;++i)
init(i);
}*/
ull a,b;
int t,n;
int f[1010][3010];
vector<int>res[1010];
int ans[1010];
void getloop(int n)
{
f[n][0]=0;
f[n][1]=1%n;
res[n].push_back(f[n][0]);
res[n].push_back(f[n][1]);
for(int i=2;;++i)
{
f[n][i]=(f[n][i-1]+f[n][i-2])%n;
res[n].push_back(f[n][i]);
if(res[n][i]==1&&res[n][i-1]==0)
{
ans[n]=i-1;
break;
}
}
}
void init()
{
for(int i=2;i<=1000;++i)
getloop(i);
}
int modpow(ull x,ull n,int mod)//a^b mod M
{
int cal=1;
for(;n;n/=2,x=x*x%mod)
if(n&1)cal=(int)(cal*x%mod);
return cal;
}
int main()
{
//test();
init();
scanf("%d",&t);
while(t--)
{
scanf("%llu%llu%d",&a,&b,&n);
//printf("%u:%u\n",n,a);
if(a==0||n==1)puts("0");
else printf("%d\n",f[n][modpow(a%ans[n],b,ans[n])]);
}
return 0;
}