我的 BSGS 和各位犇犇的差不多,但是不需要求逆元
給定一個質數 \(p\),以及一個整數 \(b\),一個整數 \(n\),現在要求你計算一個最小的非負整數 \(l\),滿足 \(b^l \equiv n \pmod p\)。
僅一行,有 \(3\) 個整數,依次代表 \(p, b, n\)。
僅一行,如果有 \(l\) 滿足該要求,輸出最小的 \(l\),否則輸出 no solution
。
5 2 3
3
注意到互質,根據尤拉定理,我們易得\(l< p\),列舉的時間複雜度為\(O(p)\)
其實可以優化到\(O(\sqrt{p})\),設 \(m=\lceil \sqrt{p}\rceil,r=b\%m\)
於是我們可以將 原式寫成
右邊好像要求逆元啊,我們不想求逆元,怎麼辦呢?
只需將式子改成
解決了問題
我們考慮找到一個 \(k\) 和 一個 \(r\) 使得上述式子成立,這個並不難
首先列舉 \(r\) ,顯然有 \(r(1\leq r\leq m)\) 注意這裡和廣大打法不同
因為廣大打法是列舉餘數,這裡列舉的是相反的
然後把右邊式子的值雜湊存下,列舉左邊的 \(k(1\leq k \leq m)\)
對於左邊列舉求出的值看看雜湊陣列是否存在對應的右邊的值,如果有,那麼就是一個解
搞出一個最小的解好像也不是很難吧.....
時間複雜度 \(O(m)\) ,也就是 \(O(\sqrt{p})\)
然後注意一下,要打很多特判
上一下碼風巨醜的程式碼
inline ll ksc(ll x, ll y, const ll& p) { return (x * y - (ll)((long double)x / p * y) * p + p) % p; }
vector<pair<ll, int> > v[ 100013];
inline ll BSGS(ll a, ll b, const ll&p) {
if (b == 1) {
if (a == 0)
return -1;
return 1;
}
if (b == 0) {
if (a == 0)
return 1;
return -1;
}
if (a == 0) {
return -1;
}
ll m = ceil(sqrt(p)), cnt = 1, res = 1;
for (int r = 1; r <= m; r++) {
cnt = ksc(cnt, a, p);//這個龜速乘不是龜速乘
v[(ksc(cnt, b, p)) % mod].push_back(make_pair(ksc(cnt, b, p), r));
}
for (int k = 1; k <= m; k++) {
res = ksc(cnt, res, p);
ll id=res%mod;
if (v[id].size())
{
for (int j = v[id].size() - 1; j >= 0; j--)
{
if (v[id][j].first ==res)
{
return m * k - v[id][j].second;
}
}
}
}
return -1;
}
給定 \(a,p,b\),求滿足 \(a^x≡b \pmod p\) 的最小自然數 \(x\) 。
每個測試檔案中包含若干組測試資料,保證 \(\sum \sqrt p\le 5\times 10^6\)。
每組資料中,每行包含 \(3\) 個正整數 \(a,p,b\) 。
當 \(a=p=b=0\) 時,表示測試資料讀入完全。
對於每組資料,輸出一行。
如果無解,輸出 No Solution
,否則輸出最小自然數解。
5 58 33
2 4 3
0 0 0
9
No Solution
對於 \(100\%\) 的資料,\(1\le a,p,b≤10^9\) 或 \(a=p=b=0\)。
注意到不互質,那我們就要想辦法讓它互質
如此反覆,直到互質為止,差不多就是
注意,操作時如果兩邊值相等了,答案就是 \(cnt\)
然後就是個普通 BSGS ,變了一點點,左邊需要乘上 \(a'\),其他都是一模一樣的
求出答案之後答案要加上 \(cnt\) ,因為我們求出的是 \(x-cnt\)
本題時限高達 4s ,就算不寫雜湊用 map 也能通過
參考如下實現
const ll mod=100003;
vector<pair<ll, int> > v[ 100013];
inline ll BSGS(ll a, ll b, const ll&p) {
memset(v,0,sizeof(v));
if (b == 1) {
if (a == 0)
return -1;
return 1;
}
if (b == 0) {
if (a == 0)
return 1;
return -1;
}
if (a == 0) {
return -1;
}
ll m = ceil(sqrt(p)), cnt = 1, res = 1;
for (int r = 1; r <= m; r++) {
cnt = ksc(cnt, a, p);
v[(ksc(cnt, b, p)) % mod].push_back(make_pair(ksc(cnt, b, p), r));
}
for (int k = 1; k <= m; k++) {
res = ksc(cnt, res, p);
ll id=res%mod;
if (v[id].size())
{
for (int j = v[id].size() - 1; j >= 0; j--)
{
if (v[id][j].first ==res)
{
return m * k - v[id][j].second;
}
}
}
}
return -1;
}
如果覺得不錯的話,就給一個贊吧!
作者是 某鄧_Duck ,轉載請註明出處
文章連結: https://www.cnblogs.com/I-am-joker/p/16320382.html
感謝您閱讀!