BZOJ5104 Fib数列 二次剩余、BSGS
发现只有通项公式可以解决考虑通项公式
\(F_n = \frac{1}{\sqrt{5}}((\frac{1+\sqrt{5}}{2})^n - (\frac{1-\sqrt{5}}{2})^n) = a\)
注意到根据二次互反律,在\(\mod 10^9+9\)意义下\(5\)存在二次剩余,所以先把\(\sqrt{5}\)对应的值算出来(实际上是\(383001016\))。
那么原式变为了\((\frac{1+\sqrt{5}}{2})^n - (\frac{1-\sqrt{5}}{2})^n = \sqrt{5}a\),\(x^n-y^n=a\)的方程好像还是不会解TAT
观察上面式子可以发现:\(\frac{1-\sqrt{5}}{2} = -\frac{1}{\frac{1 + \sqrt{5}}{2}}\),所以设\(\frac{1 + \sqrt{5}}{2} = x\),那么原式变为\(x - \frac{(-1)^n}{x} = \sqrt{5}a\)。
按照\(n\)的奇偶性讨论,可以得到一个一元二次方程,使用求根公式求出方程的解。注意到在求根公式中还有一个求\(\sqrt{\Delta}\)的操作,这里还需要计算一次二次剩余,如果这里二次剩余无解,那么方程就是无解的,否则就存在两个解。
然后我们最后的问题就是解出\((\frac{1 + \sqrt{5}}{2})^n = t\)的最小的\(n\),同时需要满足\(n\)是奇数或者是偶数。这里我们同样使用BSGS,只需要在分块的时候把块大小分成偶数,然后对于奇数和偶数分开考虑就可以了。
#include<bits/stdc++.h>
#include<tr1/unordered_map>
using namespace std;
using namespace std::tr1;
const int MOD = 1e9 + 9;
int val , g , sqrt5 , inv2;
int poww(long long a , int b){
int times = 1;
while(b){
if(b & 1) times = times * a % MOD;
a = a * a % MOD; b >>= 1;
}
return times;
}
struct BSGS{
unordered_map < int , int > odd , even , all;
int T , powbs;
void init(int base){
T = sqrt(MOD) + 1; if(T & 1) ++T;
powbs = poww(base , T);
int tms = 1;
for(int i = 0 ; i < T ; ++i , tms = 1ll * tms * base % MOD){
unordered_map < int , int > &now = i & 1 ? odd : even;
now[tms] = i; all[tms] = i;
}
}
int calc(int ans , int val){
unordered_map < int , int > &now = val == 0 ? all : (val == 1 ? odd : even);
int tms = 1ll * powbs * poww(ans , MOD - 2) % MOD;
for(int i = 1 ; i <= T ; ++i , tms = 1ll * tms * powbs % MOD)
if(now.find(tms) != now.end())
return i * T - now[tms];
return 2e9 + 1;
}
}A , B;
int findrt(){
int t = MOD - 1; vector < int > zys;
for(int i = 2 ; i * i <= t ; ++i)
if(t % i == 0){
zys.push_back(MOD / i);
while(t % i == 0) t /= i;
}
if(t - 1) zys.push_back(MOD / t);
for(int i = 2 ; ; ++i){
bool flg = 1;
for(int j = 0 ; j < zys.size() && flg ; ++j)
if(poww(i , zys[j]) == 1) flg = 0;
if(flg) return i;
}
}
int main(){
cin >> val; g = findrt(); A.init(g); sqrt5 = poww(g , A.calc(5 , 0) / 2);
val = 1ll * val * sqrt5 % MOD; inv2 = poww(2 , MOD - 2);
B.init((1ll + sqrt5) * inv2 % MOD);
int t = A.calc((1ll * val * val + MOD - 4) % MOD , 0) , ans = 2e9 + 1;
if(t % 2 == 0){
int sqt = poww(g , t / 2) , ans1 = 1ll * (val + sqt) * inv2 % MOD , ans2 = 1ll * (val - sqt + MOD) * inv2 % MOD;
ans = min(B.calc(ans1 , 1) , B.calc(ans2 , 1));
}
t = A.calc((1ll * val * val + 4) % MOD , 0);
if(t % 2 == 0){
int sqt = poww(g , t / 2) , ans1 = 1ll * (val + sqt) * inv2 % MOD , ans2 = 1ll * (val - sqt + MOD) * inv2 % MOD;
ans = min(ans , min(B.calc(ans1 , 2) , B.calc(ans2 , 2)));
}
if(ans == 2e9 + 1) puts("-1");
else cout << ans;
return 0;
}