一,定义
bsgs可以在时间内求解出问题。要求a,p互质(p为质数)
二,思想
- 由费马小定理,,显然至多枚举0~p-1次遍可知道答案
- 我们可以用i*m-j=x来表示x(m为待定常数,i,j为变量。0<=j<=m,1<=m<=p/m)。显然原式等于。
- 如果我们把右式全部枚举并存入哈希表,那么左边只需要遍历i询问哈希表中是否存在即可。复杂度是O(max(m,p/m)),当且仅当m=时最优。
- 因为枚举时可能出现i*m-j>p的情况,所以如果是求p次数内可以到达的所有x,那么需要保证i*m-j<p,否则超出p后被取模会得到错误结果。
三,模板题:P3846 [TJOI2007] 可爱的质数
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
void mysolve()
{
int a,b,mod;
cin>>mod>>a>>b;
if(__gcd(a,mod)!=1)//首先要满足a,p互质
{
cout<<"no solution"<<endl;
return;
}
int m=ceil(sqrt(mod));//m向上取整
unordered_map<int,int>mp;//哈希表
int now=1;
for(int i=0; i<=m; ++i)//哈希存入右边式子,0<=j<=m
{
if(i)now=now*a%mod;//now表示a的i次幂
mp[b*now%mod]=i;//这里有乘法记得取模
}
int ans=1;
for(int i=1; i<=m; ++i)
{
ans=ans*now%mod;//ans表示a^m的i次幂
if(mp.count(ans)&&i*m-mp[ans]<mod)
{
cout<<(i*m-mp[ans]+mod)%mod<<endl;//因为从小到达枚举,所以第一个就是最小
return;
}
}
cout<<"no solution"<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
//cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}
例题:P3306 [SDOI2013] 随机数生成器 - 洛谷
思路:
-
相邻xi有公式即等比数列
-
所以目标 转化成了bsgs裸题
-
但是注意到a=0与a=1需要特判处理,不满足上式
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int long long
int p,a,b,x,t;
ll fastmi(int base,int power)
{
ll ans=1;
while(power)
{
if(power&1)ans=ans*base%p;
base=base*base%p;
power>>=1;
}
return ans;
}
void mysolve()
{
cin>>p>>a>>b>>x>>t;
if(x==t)
{
cout<<1<<endl;
return;
}
if(a==0)
{
if(b==t)cout<<2<<endl;
else cout<<-1<<endl;
return;
}
else if(a==1)
{
if(!b)cout<<-1<<endl;
else cout<<(t-x+p)%p*fastmi(b,p-2)%p+1<<endl;
return;
}
int m=ceil(sqrt(p));
int now=1,tmp=b*fastmi(a-1,p-2)%p;
b=(t+tmp)*fastmi(x+tmp,p-2)%p;
unordered_map<int,int>mp;
for(int i=0; i<=m; ++i)//j从0到m
{
if(i)now=now*a%p;
mp[b*now%p]=i;
}
int ans=1;
for(int i=1; i<=m; ++i)
{
ans=ans*now%p;
if(mp.count(ans)&&i*m-mp[ans]<p)
{
cout<<(i*m-mp[ans]+p)%p+1<<endl;
return;
}
}
cout<<-1<<endl;
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
ll t=1;
cin >> t;
while (t--)
{
mysolve();
}
system("pause");
return 0;
}