ABC222 G - 222(数论)

ABC222 G - 222

解题思路

首先看到题目我们发现,对于 \(99983\)\(2\) 等数字答案都等于这个数本身 \(-1\)。我们又发现这些数是质数,非常自然想到费马小定理。但是赛时我只想到了这一点,并没有把费马小定理推广到欧拉函数上。而这是解题的关键。

我们知道,对于任意的 \(x\),对于\(\gcd(a,x)=1\)有:

\[a^{\varphi (x)}\equiv 1\mod x \]

这就是欧拉定理。问题是我们如何与这道题联系起来呢?我们其实很容易对于一个数 \(x=2\cdot k\ \ (k\in Z)\) 若有 \(x\mid 222\dots222\),一定有 \(k\mid 111\dots 111\)。这有什么用呢?我们可以在想一步,若对于 \(x=2\cdot k+1\ \ (k\in Z)\) 我们有 \(x\mid 111\dots 111\)

然后怎么办?我们尝试找一下 \(111\dots 111\) 的性质,发现它其实可以表示为 \(\frac{10^n-1}9\) 的形式。这好像和欧拉定理可以联系上了。同上面的变化方式,我们可以将 \(x\) 或者 \(k\) 乘上 \(9\),使得得到的新数 \(x'\) 满足 \(x'\mid 10^n-1\)

是不是柳暗花明又一村了?我们可以进一步推柿子。

\[10^n\equiv 1\mod x' \]

那我们就要找最小的满足条件的 \(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;
}
posted @ 2021-10-11 22:40  huayucaiji  阅读(217)  评论(0编辑  收藏  举报