ABC222 G - 222
解题思路
首先看到题目我们发现,对于 (99983) 和 (2) 等数字答案都等于这个数本身 (-1)。我们又发现这些数是质数,非常自然想到费马小定理。但是赛时我只想到了这一点,并没有把费马小定理推广到欧拉函数上。而这是解题的关键。
我们知道,对于任意的 (x),对于(gcd(a,x)=1)有:
这就是欧拉定理。问题是我们如何与这道题联系起来呢?我们其实很容易对于一个数 (x=2cdot k (kin Z)) 若有 (xmid 222dots222),一定有 (kmid 111dots 111)。这有什么用呢?我们可以在想一步,若对于 (x=2cdot k+1 (kin Z)) 我们有 (xmid 111dots 111)。
然后怎么办?我们尝试找一下 (111dots 111) 的性质,发现它其实可以表示为 (frac{10^n-1}9) 的形式。这好像和欧拉定理可以联系上了。同上面的变化方式,我们可以将 (x) 或者 (k) 乘上 (9),使得得到的新数 (x') 满足 (x'mid 10^n-1)。
是不是柳暗花明又一村了?我们可以进一步推柿子。
那我们就要找最小的满足条件的 (n)。由欧拉定理,(varphi(x')) 一定满足条件(只要 (gcd(x',10)=1))。那么我们输出 (varphi(x')) 就可以了吗?
达咩达咩。
我们发现对于 (x=37),(n=3) 就满足条件。也就是说,(varphi(x')) 不一定是最小的满足条件的数。满足条件的最小的 (n) 一定是 (varphi(x')) 的约数。
我们 (O(sqrt x)) 求出 (varphi(x)),再用 (O(sqrt {varphi(x)})) 算出答案即可。
总时间复杂度为(O(T sqrt n))。问题解决。
代码
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
//忽略这个 @zdm
using namespace std;
int read() {
char ch=getchar();
int f=1,x=0;
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
int n;
int qpow(int x,int y,int m) {
int ret=1;
while(y) {
if(y&1) {
ret=ret*x%m;
}
x=x*x%m;
y>>=1;
}
return ret;
}
int phi(int x) {
int ret=x;
for(int i=2;i*i<=x;i++) {
if(x%i==0) {
ret=ret/i*(i-1);
}
while(x%i==0) {
x/=i;
}
}
if(x>1) {
ret=ret/x*(x-1);
}
return ret;
}
int check(int x,int phix) {
int ans=x+1;
for(int i=1;i*i<=phix;i++) {
if(phix%i==0) {
if(qpow(10,i,x)==1) {
return i;
//若这个 i 满足条件一定是最优的
//直接返回
}
else if(qpow(10,phix/i,x)==1) {
ans=phix/i;
//否则要再取 min(直接更新即可,因为这个值单调减)
}
}
}
return ans==x+1? -1:ans;
}
signed main() {
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int t=read();
while(t--) {
int x=read();
if(x&1) {
x=x*9;//转换 x->x'
}
else {
x=x/2*9;
}
cout<<check(x,phi(x))<<endl;
}
//fclose(stdin);
//fclose(stdout);
return 0;
}