Luogu | P4780 Phi 的反函数 | 数学 | 欧拉函数
Description
请求出最小的正整数 $x$ ,使得 $\phi_x = N$。
Input Format
一行一个正整数 $N$ 。
Output Format
输出 $x$ ,若 $x$ 不存在或者 $x > 2^{31}$,输出 $-1$。
Input Sample
Sample 01
4
Output Sample
Sample 01
5
Data Range
$1 \le N \le 2^{31}$。
Solution
显然 $\phi$ 在其定义域上无单调性,故只能用 DFS 枚举。
根据 $\phi$ 的定义,考虑筛出 $\sqrt{2^{31}}$ 以内的所有质数,然后进行 DFS 。观察数据范围,可以发现,范围内的数字最多由 $10$ 个不同质数组成,每个质数最多有 $30$ 个。所以数据范围较小。
根据 $\phi$ 的部分积性和递推求法,可以发现,设当前还剩的 $\phi$ 为 $p$ ,当前已经形成的数字为 $x$ 。当 $p$ 内存在因子 $e$并且 $e+1$ 是一个质数,则可以将该 $e+1$ 乘进 $x$ 内,再从 $p$ 中分离质因子 $e$ 。可能出现剩下 $p+1$ 是一个大于 $\sqrt N$ 的大质数的情况,那么将对应的 $p+1$ 乘进 $x$ 即可。
Code
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define swap(x,y) {int t=x; x=y,y=t;}
#define wipe(x,y) memset(x,y,sizeof(x))
#define dbgIn(x) freopen(x".in","r+",stdin)
#define rep(x,y,z) for(int x=y,I=z;x<=I;++x)
#define dbgOut(x) freopen(x".out","w+",stdout)
#define file(x) freopen(x".in","r+",stdin); freopen(x".out","w+",stdout)
inline void Read(int &x){
x=0; char ch=0; while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar(); return;
}
int N;
int cnt;
long long ans=4294967296;
int primes[50005];
bool isprime[50005];
void Euler_Sieve(int lim){
rep(i,2,lim){
if(!isprime[i])
primes[++cnt]=i;
for(int j=1;j<=cnt&&i*primes[j]<=lim;j++){
isprime[i*primes[j]]=1;
if(i%primes[j]==0)
break;
}
}
return;
}
bool isPrime(int a){
if(a<0)
return false;
for(int i=1;primes[i]*primes[i]<=a;i++){
if(a%primes[i]==0)
return false;
}
return true;
}
void DFS(int step,long long Phi,long long num){
if(Phi==1){
ans=min(ans,num);
return;
}
if((Phi*Phi>N)&&isPrime(Phi+1)){
if((Phi+1)*num<ans)
ans=min(ans,(Phi+1)*num);
return;
}
rep(i,step,cnt){
if(Phi%(primes[i]-1)==0){
long long Next=Phi;
long long Num=num;
while(Next%(primes[i]-1)==0){
Next/=(primes[i]-1);
Num*=primes[i];
if(Num<0||Num>ans) break;
DFS(i+1,Next,Num);
}
}
}
return;
}
int main(){
Read(N);
Euler_Sieve(46340);
if(isPrime(N+1)){
printf("%d\n",N+1);
return 0;
}
DFS(1,N,1);
printf("%lld\n",ans==4294967296?-1:ans);
return 0;
}