房间的铁门上有一个按钮,还有一个显示屏显示着“1”。
旁边还有一行小字:“这是一个高精度M进制计算器,每按一次按钮,屏幕上的数便会乘以K。当个位数再次变为1时,门就开了。”
由于Ada急于出去,所以你要在1s之内求出她的最小按键次数。
首先我们看到题目,每次在(M)进制下对(1)乘(k),也就是对(k)乘方,最后还是得到(1)
这样我们就可以列出同余方程(k^xequiv 1 (mod M))
而初始状态为(1),即(k^0=1)
所以答案就是满足方程的最小的正整数(x)
其实这道题是( ext{Ex\_BSGS}),因为题目不满足(k)和(M)互质
考虑我们在做( ext{Ex\_BSGS})时,每次取出(g=gcd(k,M),b'=frac{b}{g},M'=frac{M}{g},k'=frac{k}{g})
得到新方程(k^{x-1} imes k'equiv b' (mod M'))
移项得到(k^{x-1}equiv frac{b'}{k'} (mod M'))
无解的情况就是(g mid b)并且(b e1)
证明就不证了,不会的可以去看这篇文章QAQ
直到(g=1),即(k),(M)互质,就可以用(BSGS)求解了
而题目给的(b)是(1),那么我们回去看这个过程,(k,M)不互质说明(g>1)
[g>1,x
e0Rightarrow g
mid bRightarrow ext{无解}
]
所以这个题特判下(k,M)互不互质然后跑(BSGS)就好了
简单说下(BSGS)怎么写吧
设(n=left lfloor sqrt M ight floor,x=i imes n-j,1le i,jle n),原方程就变为
[k^{i imes n-j}equiv 1 (mod M)
]
[(k^n)^iequiv k^j (mod M)
]
然后把(k^j)求出来哈希一下就可以啦
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <cmath>
#define int long long
using namespace std;
int m,k;
map <int,int> f;
int mypow(int a,int x,int p) //快速幂
{
int s=1;
while (x)
{
if (x&1)s=s*a%p;
a=a*a%p;
x>>=1;
}
return s;
}
int gcd(int a,int b) //最大公约数
{
if (!b)return a;
return gcd(b,a%b);
}
signed main()
{
cin>>m>>k;
if (gcd(m,k)!=1) //特判无解
{
cout<<"Let's go Blue Jays!"<<endl;
return 0;
}
int n=ceil(sqrt(m)),b=1;
for (int i=1;i<=n;i++) //k^j
{
b=b*k%m;
f[b]=i;
}
b=1;
int tmp=mypow(k,n,m);
for (int i=1;i<=n;i++) //(k^n)^i
{
b=b*tmp%m;
if (f[b]&&(i*n-f[b]+m)%m!=0) //有解且不为0
{
cout<<(i*n-f[b]+m)%m<<endl;
return 0;
}
}
cout<<"Let's go Blue Jays!"<<endl; //无解
return 0;
}