-
¿¡
众所周知两个整数和可以表示为其中互质。
那么,也就是和的最大公约数。
这里有一个的定义式(其中表示):
那么,我们的中心就是转移到了求上面。
这里先上结论:
证明:
。
那好,那么代码实现就极其容易了,如下:
ll gcd(ll a,ll b){ if(b) return gcd(b,a%b); return abs(a); }
-
不定方程。
此处设。
题目要求求中,的最小值。
假设一组解满足。
那么,我们就能得出:。
现在,求出就是我们的唯一目标。
但是,此处求出最小解,就犹如大海捞针,我们需要一步步来,先求出一组可能的解。
于是,我们想到了取模的定义。
,其中表示向下取整。
所以:
也就是说,利用小学数学,我们可以得到:
但是,所以,命中注定的一组解已经写下:
那么,怎么求呢?
我们列出和有关的式子。
然后发现,除了系数的改变,我们啥都没改,一切都和原来的一样。
然后,我脱口而出:
我们需要一个,一个,使得。
天哪,这不就是吗?
于是,我们就可以到达最极端的那头:
。
然后就可以一层一层求出这个解了(
虽然不是最小的)。代码:
inline ll exgcd(ll &x,ll &y,ll a,ll b){ if(b==0){ x=1;y=0; return a; } ll dl=exgcd(x,y,b,a%b); int z=x; x=y; y=z-y*(a/b); return dl; }
-
快速幂
ull ksm(ull a,ull b){ ull ans = 1,base=a; while(b){ if(b&1){ ans*=base; } base*=base; b>>=1; } return ans; }
大致思路:先把拆成二进制形式,每次查看最后一位,如果是的话就乘上,是就不管它,而对于每一轮,同时变成平方,而最初时,表示
初始化要设成,因为有
代码这么短背一背就行了 -
BSGS
这个方法用于解方程。
假设是向上取整。
所以就有。
然后我们需要枚举,存到hash表里边。
接下来就是枚举直到满足。
如果存在的话那么此处肯定是最小的。
代码:
#include<bits/stdc++.h>
#define ns "-1"
#define fs(i,x,y,z) for(ll i=x;i<=y;i+=z)
#define ft(i,x,y,z) for(ll i=x;i>=y;i+=z)
#define ll long long
#define ull unsigned long long
#define db double
#define ms(a,b) memset(a,b,sizeof(a))
#define sz(a) sizeof(a)
using namespace std;
const int N=100001,inf=0x7f7f7f7f;
map<ll,int>mp;
ll p,a,b,n,m,now,ans,t;
bool flag;
ll ksm(ll a,ll b){
ll ans=1,base=a;
while(b){
if(b&1){
ans*=base;
ans%=p;
}
base*=base;
base%=p;
b>>=1;
}
return ans%p;
}
int main(){
cin>>p>>b>>n;
if(b%p==0){
cout<<"no solution";
return 0;
}
m=ceil(sqrt(p));
mp[n%p]=0;
fs(i,1,m,1){
mp[ksm(b,i)*n%p]=i;
}
t=ksm(b,m);
now=1;
fs(i,1,m,1){
now=(now*t)%p;
if(mp[now]){
flag=1;
ans=i*m-mp[now];
cout<<(ans%p+p)%p;
return 0;
}
}
cout<<"no solution";
return 0;
}