Admission to Exam
题链
\(n\) 个数,\(x,2x,3x\cdots,nx\),它们对 \(n\) 取模的结果均匀地散布在 \([0,n-1]\) 的整点上。这个条件等价于 \(x\) 与 \(n\) 互质。
那么这道题就是求 \(\varphi(n)=k\) 的最小的 \(n\)。
由刚刚利用积性函数线性筛类似的思想。
考虑可以将 \(k\) 进行质因子拆分,考虑每个质因子是由什么贡献而来的。
那么对于每个 \(p_i\),第一次出现时贡献为 \((p_i-1)\),之后出现的贡献为 \(p_i\)。
-
若 \((p_i+1)\in prime\) 且当前是第一次出现 \((p_i+1)\) 这个质数,那么答案乘上 \((p_i+1)\),否则,不进行该操作。
-
若 \(p_i\in prime\) 且当前并非第一次出现 \(p_i\) 这个质数,那么答案乘上 \(p_i\),否则,不进行该操作。
这两个操作都会使得 \(n\) 除以 \(p_i\),转化成它的子问题。
我感觉分析到这里,还是有一些漏洞,需要证明一些东西:除了 \(2\) 和 \(3\) 以外,不存在 \(p-1\) 和 \(p\) 满足它们都是质数。
首先证明:对于任意质数 \(p\),除 \(2\) 和 \(3\) 以外,都有:\(p\equiv 1 \ \ or \ \ 5 \pmod 6\)。
这个非常好证,因为枚举其余的余数,会发现它们都可以表示为 \(2\) 或 \(3\) 的倍数。
那么对于质数 \(p-1\),它模 \(6\) 的结果要么是 \(1\) 要么是 \(5\),加 \(1\) 以后必定不是质数。
至此,证毕。
于是暴力拆分出的质因数,在不是 \(2\) 或 \(3\) 的时候,可以直接搞,那么现在的问题就是要求 \(\varphi(n)=2^x\times 3^y\) 的最小的 \(n\)。
由前面那两个操作会发现,对于 \(2\) 这个质因子,若是存在 \(3\),它需要拿一个去给 \(3\) 填一次坑。
其实分析到这里大致写法就已经出来了。
从大到小选择质数。
注意一下筛根号以内的质数最后可能还会剩余一个大于根号的质数减 \(1\),需要特判一下。
但是这个特判并没有那么简单,应当是要考虑是否需要这个质因子再下定论的。
艹,好像没有那么简单。
网上似乎搜不到题解。不清楚自己的思路哪里挂了,等下若是有时间打个对拍吧。
写出了一个 T 的代码,仔细想了想,这道题的 \(n\) 可能大到离谱,这种看不懂网上也搜不到代码和题解的屑题不打算继续写了。
#include <algorithm>
#include <stdio.h>
#include <cmath>
#include <map>
#define LL long long
using namespace std;
const int N=1e6+3;
inline int rin()
{
int s=0;
bool bj=false;
char c=getchar();
for(;(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')bj=true,c=getchar();
for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
if(bj)s=-s;
return s;
}
inline LL min(LL x,LL y){return x<y?x:y;}
int lens;
int d[N];
int tail;
bool pri[N];
inline void make_prime(int n)
{
n++;
lens=sqrt(n);
pri[1]=true;
for(int i=2;i<=lens;i++)
{
if(!pri[i])d[++tail]=i;
for(int j=1;j<=tail;j++)
{
int now=i*d[j];
if(now>lens)break;
pri[now]=true;
if(i%d[j]==0)break;
}
}
return;
}
int a[N];
int cutt;
map<int,bool>q;
inline void make_in(int now)
{
if(now==1||q[now])return;
q[now]=true;a[++cutt]=now;
for(int i=1;i<=tail;i++)
{
if(now%d[i])continue;
make_in(now/d[i]);
}
return;
}
bool pri_a[N];
bool pri_b[N];
inline void init(int n)
{
int nt=cutt;
for(int i=1;i<=nt;i++)
{
int now=n/a[i];
if(now==1||q[now])continue;
a[++cutt]=now;
}
sort(a+1,a+cutt+1);
for(;cutt&&a[cutt]>lens;cutt--);
for(int i=1;i<=cutt;i++)
{
int now=a[i];
if(now<=lens)pri_a[i]=pri[now];
else
{
int ed=sqrt(now);
pri_a[i]=false;
for(int j=1;j<=tail&&d[j]<=ed;j++)if(now%d[j]==0){pri_a[i]=true;break;}
}
}
for(int i=1;i<=cutt;i++)
{
int now=a[i]+1;
if(now<=lens)pri_b[i]=pri[now];
else
{
int ed=sqrt(now);
pri_b[i]=false;
for(int j=1;j<=tail&&d[j]<=ed;j++)if(now%d[j]==0){pri_b[i]=true;break;}
}
}
// for(int i=1;i<=cutt;i++)printf("%d ",a[i]);printf("\n");
// for(int i=1;i<=cutt;i++)printf("%d ",pri_a[i]);printf("\n");
// for(int i=1;i<=cutt;i++)printf("%d ",pri_b[i]);printf("\n");
return;
}
LL ans=0x3f3f3f3f3f3f3f3f;
// inline void dfs(int k,LL n)
// {
// // printf("k:%d\n",k);
// if(k==1)
// {
// ans=min(ans,n);
// return;
// }
// for(int i=1;i<=cutt&&a[i]<=k;i++)
// {
// if(k%a[i])continue;
// if(!pri_a[i]&&(n%a[i]==0))dfs(k/a[i],n*a[i]);
// if(!pri_b[i]&&(n%(a[i]+1)))dfs(k/a[i],n*(a[i]+1));
// }
// }
int qy[8]={2,3,5,7,11,13,17,19};
inline bool Miller_Rabin(int a,int p)
{
int now=p-1;
int cts=0;
LL sum=1;
for(;now%2==0;now>>=1)cts++;
for(LL s=a;now;now>>=1){if(now&1)sum=sum*s%p;s=s*s%p;}
for(;cts;cts--)
{
LL nxt=sum*sum%p;
if(nxt==1&&sum!=1&&sum!=p-1)return false;
sum=nxt;
}
return (sum==1LL);
}
inline bool prime_(int p)
{
if(p==1)return false;
if(p==2)return true;
if((p-1)&1)return false;
for(int i=0;i<8;i++)if(p==qy[i])return true;
if(p<=qy[7])return false;
for(int i=0;i<8;i++)if(!Miller_Rabin(qy[i],p))return false;
return true;
}
inline void dfs(int k,LL n,int x)
{
// printf("%d %lld %d\n",k,n,x);
if(k>lens)
{
bool if_true=false;
if(n%k==0&&prime_(k))
{
ans=min(ans,n*k);
if_true=true;
}
if(prime_(k+1))
{
// printf("n:%lld k:%d\n",n,k);
ans=min(ans,n*(k+1));
return;
}
if(if_true)return;
}
if(x>cutt)
{
if(k==1)ans=min(ans,n);
return;
}
dfs(k,n,x+1);
if(k%a[x])return;
if(!pri_b[x]&&(n%(a[x]+1)))k/=a[x],n*=(a[x]+1);
dfs(k,n,x+1);
for(;k%a[x]==0;)
{
if(!pri_a[x]&&(n%a[x]==0))k/=a[x],n*=a[x];
else return;
dfs(k,n,x+1);
}
return;
}
int main()
{
int i,j;
int k=rin();
make_prime(k);
make_in(k);
init(k);
dfs(k,1,1);
printf("%lld\n",(ans==0x3f3f3f3f3f3f3f3f)?(0):(ans));
return 0;
}