HDU3977 Evil teacher 求fib数列模p的最小循环节
Here f(n) is the n-th fibonacci number (n >= 0)! Where f(0) = f(1) = 1 and for any n > 1, f(n) = f(n - 1) + f(n - 2). For example, f(2) = 2, f(3) = 3, f(4) = 5 ...
The teacher used to let you calculate f(n) mod p where n <= 10^18 and p <= 10^9, however , as an ACMER, you may just kill it in seconds! The evil teacher is mad about this. Now he let you find the smallest integer m (m > 0) such that for ANY non-negative integer n ,f(n) = f(n + m) (mod p) . For example, if p = 2, then we could find know m = 3 , f(0) = f(3) = 1(mod 2), f(1) = f(4) (mod 2) ....
Now the evil teacher will only give you one integer p( p <= 2* 10^9), will you tell him the smallest m you can find ?
Input
The first line is one integer T indicates the number of the test cases. (T <=20)
Then for every case, only one integer P . (1 <= P <= 2 * 10^9, the max prime factor for P is no larger than 10^6)
Output
Output one line.
First output “Case #idx: ”, here idx is the case number count from 1.Then output the smallest m you can find. You can assume that the m is always smaller than 2^64 .
Sample Input
5 11 19 61 17 67890
Sample Output
Case #1: 10 Case #2: 18 Case #3: 60 Case #4: 36 Case #5: 4440
题目让我们做什么呢,求fib数列模p的最小循环节,但是这个题目的素数一定是小于10^6,所以有下面这个水水的做法
对每一个形如p^k的数计算循环节,它们的最小公倍数就是n的循环节长度(当然这里面涉及到CRT等等方面的基础)。那么现在问题就是计算p^k的循环节,这个问题可以进一步简化成求G(p)*p^(k-1)
求fib数列模p(p是素数)的最小循环节方法:
暴力枚举fib[i]%p==0的最小的i,然后记录pos=i+1,设a为fib[i]%p==0的前一位数,即a=fib[i-1]
那么我们知道fib数列模p的最小循环节长度一定是pos*x,那么也就是说现在要求一个最小的数x
满足,
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll Lcm(ll a,ll b) { return a/__gcd(a,b)*b; } inline ll Pow(ll a,ll b,ll p) { ll ans=1; for(; b; b>>=1,a=a*a%p)if(b&1)ans=ans*a%p; return ans; } const int N=1e6+5; int prime[N],tot,vis[N]; inline void Pre() { for(int i=2; i<N; i++) { if(!vis[i]) prime[++tot]=i; for(int j=1; j<=tot&&1LL*prime[j]*i<N; j++) { vis[prime[j]*i]=1; if(i%prime[j]==0)break; } } } inline ll calc(ll p) { ll a=3,f1=1,f2=1,f3=2%p; while(f3) f1=f2,f2=f3,f3=(f1+f2)%p,a++; ll ans=p-1; for(int i=1; 1LL*i*i<p; i++) if((p-1)%i==0) { if(Pow(f2,i,p)==1) ans=min(ans,1LL*i); if(Pow(f2,(p-1)/i,p)==1) ans=min(ans,1LL*(p-1)/i); } return ans*a; } inline ll Solve(ll n) { ll ans=0; for(int i=1; prime[i]<=n; i++) if(n%prime[i]==0) { ll tmp=1; while (n%prime[i]==0) n/=prime[i],tmp*=prime[i]; tmp=tmp/prime[i]*calc(prime[i]); ans=!ans?tmp:Lcm(ans,tmp); } return ans; } int main() { int T,n,ca=0; Pre(),scanf("%d",&T); while(T--)scanf("%d",&n),printf("Case #%d: %I64d\n",++ca,n==1?1:Solve(n)); return 0; }
数字变大呢,就是解特征值了,不会啊
本文来自博客园,作者:暴力都不会的蒟蒻,转载请注明原文链接:https://www.cnblogs.com/BobHuang/p/9772686.html