【NOIP 模拟题】【bzoj 3643】Phi的反函数(数论+搜索)
【题解】【数论+dfs】
【其实题面已经昭示了该怎么做,因为做法就是上面给的两个式子。】
【那么,由题意:筛素数,然后直接dfs查找,暴力凑(p1-1) * (p2-1) * …… * (pm-1),然后将n与其相除后验证是否是这些数的倍数即可。】
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int prime[100010],cnt,n,m;
bool vis[100010];
ll ans;
inline void search()
{
for(int i=2;i<=50000;++i)
{
if(!vis[i]) prime[++cnt]=i;
for(int j=1;j<=cnt;++j)
{
if(i*prime[j]>50000) break;
vis[i*prime[j]]=1;
if(!(i%prime[j])) break;
}
}
}
inline bool pd(ll x)
{
ll k=sqrt(x);
for(int i=1;i<=cnt;++i)
{
if(prime[i]>k) break;
if(!(x%prime[i])) return 0;
}
return 1;
}
void dfs(int last,int now,ll sum)
{
if(sum>=ans) return;
if(now==1) {ans=sum; return;}
if(now>m&&pd(now+1)) ans=min(ans,sum*((ll)now+1));
for(int i=last+1;i<=cnt;++i)
{
if(prime[i]-1>m) break;
if(prime[i]-1>now) break;
if(!(now%(prime[i]-1)))
{
int x=now/(prime[i]-1);
ll y=sum*prime[i];
dfs(i,x,y);
while(!(x%prime[i]))
{
x/=prime[i]; y*=prime[i];
dfs(i,x,y);
}
}
}
}
int main()
{
freopen("phi.in","r",stdin);
freopen("phi.out","w",stdout);
int i,j;
search();
scanf("%d",&n);
ans=2147483648; m=sqrt(n);
dfs(1,n,1);
if(ans>=2147483648) printf("-1\n");
else printf("%I64d\n",ans);
return 0;
}
既然无能更改,又何必枉自寻烦忧