我的 BSGS 和各位犇犇的差不多,但是不需要求逆元
Luogu [ TJOI2007 ] 可愛的質數
原題展現
題目描述
給定一個質數 \(p\),以及一個整數 \(b\),一個整數 \(n\),現在要求你計算一個最小的非負整數 \(l\),滿足 \(b^l \equiv n \pmod p\)。
輸入格式
僅一行,有 \(3\) 個整數,依次代表 \(p, b, n\)。
輸出格式
僅一行,如果有 \(l\) 滿足該要求,輸出最小的 \(l\),否則輸出 no solution
。
樣例 #1
樣例輸入 #1
5 2 3
樣例輸出 #1
3
資料規模與約定
- 對於所有的測試點,保證 \(2\le b,n < p<2^{31}\)。
Baby Steps Giant Steps 詳解
注意到互質,根據尤拉定理,我們易得\(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;
}
SPOJ3105 MOD
原題展現
題目描述
給定 \(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
,否則輸出最小自然數解。
樣例 #1
樣例輸入 #1
5 58 33
2 4 3
0 0 0
樣例輸出 #1
9
No Solution
資料範圍
對於 \(100\%\) 的資料,\(1\le a,p,b≤10^9\) 或 \(a=p=b=0\)。
擴充套件 Baby Steps Giant Steps 詳解
注意到不互質,那我們就要想辦法讓它互質
如此反覆,直到互質為止,差不多就是
注意,操作時如果兩邊值相等了,答案就是 \(cnt\)
然後就是個普通 BSGS ,變了一點點,左邊需要乘上 \(a'\),其他都是一模一樣的
求出答案之後答案要加上 \(cnt\) ,因為我們求出的是 \(x-cnt\)
本題時限高達 4s ,就算不寫雜湊用 map 也能通過
參考如下實現
vector<pair<ll, int> > v[ 1000013];
int vis[1000003];
inline ll exBSGS(ll a,ll b,ll p)
{
memset( vis,0,sizeof(vis));
if(p==0)return -1;
if(p==1)
{
if(b==0)return 0;
return -1;
}
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 ak=0,t=1,d=gcd(a,p);
while(d!=1)
{
ak++;
t*=a;
t/=d;
p/=d;
if(b%d!=0)return -1;
b/=d;
if(t%p==b%p)return ak;
d=gcd(a,p);
t%=p;
}
ll m = ceil(sqrt(p)), res=t%p,cnt=1;
for (int r = 1; r <= m; r++) {
cnt = ksc(cnt, a, p);
ll hash=(ksc(cnt, b, p)) % mod;
if(vis[hash]==0)
{
vis[hash]=1;
v[hash].clear();
}
v[hash].push_back(make_pair(ksc(cnt, b, p), r));
}
for (int k = 1; k <= m; k++) {
res = ksc(cnt, res, p);
ll hash=res%mod;
if (vis[hash])
{
for (int j = v[hash].size() - 1; j >= 0; j--)
{
if (v[hash][j].first ==res)
{
return m * k - v[hash][j].second+ak;
}
}
}
}
return -1;
}