正题
题目链接:https://www.luogu.com.cn/problem/P2485
题目大意
给出a,b,pa,b,pa,b,p要求一下一种
- ab%pa^b\% pab%p的值
- ax≡b(modp)ax\equiv b(\mod p)ax≡b(modp)的最小非负整数解
- ax≡b(modp)a^x\equiv b(\mod p)ax≡b(modp)的最小非负整数解
解题思路
一道缝合题
第一个直接套快速幂就好了,时间复杂度O(logn)O(\log n)O(logn)。
第二个是exgcdexgcdexgcd,考虑如何求ax+by=cax+by=cax+by=c
根据裴蜀定理我们对于方程ax+by=gcd(a,b)ax+by=gcd(a,b)ax+by=gcd(a,b)一定有解,考虑求出这组解。
ax+by=gcd(a,b)=gcd(b,a%b)=gcd(b,a−b⌊ab⌋)ax+by=gcd(a,b)=gcd(b,a\% b)=gcd(b,a-b\lfloor\frac{a}{b}\rfloor)ax+by=gcd(a,b)=gcd(b,a%b)=gcd(b,a−b⌊ba⌋)
ax+by=bx′+(a−b⌊ab⌋)y′ax+by=bx'+(a-b\lfloor\frac{a}{b}\rfloor)y'ax+by=bx′+(a−b⌊ba⌋)y′
ax+by=ay′+b(x′−⌊ab⌋y′)ax+by=ay'+b(x'-\lfloor\frac{a}{b}\rfloor y')ax+by=ay′+b(x′−⌊ba⌋y′)
故有x=y′,y=x′−⌊ab⌋y′x=y',y=x'-\lfloor\frac{a}{b}\rfloor y'x=y′,y=x′−⌊ba⌋y′
求gcdgcdgcd的时候顺便求解就好了。
那得到这组x0,y0x_0,y_0x0,y0以后,如果ccc是gcd(a,b)gcd(a,b)gcd(a,b)的倍数那么才有解,而这个方程的通解就是{x=x0∗cd+k∗d∗by=y0∗cd−k∗d∗a\left \{ \begin{matrix}x=x_0*\frac{c}{d}+k*d*b\\y=y_0*\frac{c}{d}-k*d*a\end{matrix}\right.{x=x0∗dc+k∗d∗by=y0∗dc−k∗d∗a
然后拿最小的那组就好了,时间复杂度O(logn)O(\log n)O(logn)
第三个是BSGSBSGSBSGS
定义t=pt=\sqrt pt=p那么axa^xax就可以表示为ai∗t−ja^{i*t-j}ai∗t−j
然后ai∗t−j≡b(modp)a^{i*t-j}\equiv b(\mod p)ai∗t−j≡b(modp)
ai∗t≡b∗ajmodp)a^{i*t}\equiv b*a^j\mod p)ai∗t≡b∗ajmodp)
因为b∗ajb*a^jb∗aj最多只有ttt种,我们用mapmapmap存下来
然后枚举ai∗ta^{i*t}ai∗t的值与mapmapmap中的对应即可。因为有mapmapmap所以时间复杂度为O(nlogn)O(\sqrt n\log n)O(nlogn),用hashhashhash理论可以优化到O(n)O(\sqrt n)O(n)
需要注意的是at%p=0a^t\%p=0at%p=0时,当且仅当b=1b=1b=1时有解为000。
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define ll long long
using namespace std;
ll T,K,a,b,p;
map<ll,ll> mp;
void work1(ll a,ll b,ll p){ll ans=1;while(b){if(b&1)ans=ans*a%p;a=a*a%p;b>>=1;}printf("%lld\n",ans);return;
}
ll exgcd(ll a,ll b,ll &x,ll &y){if(!b){x=1;y=0;return a;}ll d=exgcd(b,a%b,x,y);ll z=x;x=y;y=z-a/b*y;return d;
}
void work2(ll a,ll b,ll p){ll x,y;ll d=exgcd(a,p,x,y);if(b%d){printf("Orz, I cannot find x!\n");return;}x*=b/d;y*=b/d;printf("%lld\n",(x%(d*p)+d*p)%(d*p));
}
ll power(ll x,ll b,ll p){ll ans=1;while(b){if(b&1)ans=ans*x%p;x=x*x%p;b>>=1;}return ans;
}
void work3(ll a,ll b,ll p){mp.clear();ll t=(int)sqrt(p)+1;for(ll i=0;i<t;i++)mp[b]=i,b=b*a%p;a=power(a,t,p);if(a==0&&b==1){printf("1\n");return;}else if(a==0) {printf("Orz, I cannot find x!\n");return;}ll tmp=1,ans=1e18;for(ll i=0;i<=t;i++){ll j=(mp.find(tmp)!=mp.end())?mp[tmp]:-1;if(j>=0&&i*t-j>=0)ans=min(ans,i*t-j);tmp=tmp*a%p;}if(ans==1e18)printf("Orz, I cannot find x!\n");else printf("%lld\n",ans);
}
int main()
{scanf("%lld%lld",&T,&K);while(T--){scanf("%lld%lld%lld",&a,&b,&p);if(K==1)work1(a%p,b,p);if(K==2)work2(a%p,b%p,p);if(K==3)work3(a%p,b%p,p);}
}