题意
给100个数,找到在欧拉函数中连续出现的位置,找不到输出 -1
题解
在素数密度较大的情况下,想到最大的数
x
x
x ,
x
+
1
x+1
x+1 应该是一个素数
所以判断一下是否为素数,检查100个是否都满足即可
但是,打表发现,会出现相邻素数的距离大于100,那么上面的方法就不适用了
考虑一个性质
当
n
,
m
n,m
n,m 互质时
φ
(
n
∗
m
)
=
φ
(
n
)
∗
φ
(
m
)
=
(
n
−
1
)
∗
(
m
−
1
)
\varphi (n*m)=\varphi (n)*\varphi(m)=(n-1)*(m-1)
φ(n∗m)=φ(n)∗φ(m)=(n−1)∗(m−1)
最大的数,应该能分解为两个素数的欧拉函数的乘积
证明的话,我也不明白。。。
然后暴力分解,判断即可
由于求欧拉函数的次数较多,所以要用 n 1 4 n^{\frac{1}{4}} n41 的求法
其实,用 M i l l e r _ R a b i n Miller\_Rabin Miller_Rabin 判断 i n t int int 范围内的素数不是最优的选项,实际中,要检测10多个才能保证正确,换用其他的素数检测效率会跟更高,而且不是基于概率的。
代码
#include<bits/stdc++.h>
#define N 1000010
#define INF 0x3f3f3f3f
#define eps 1e-6
#define pi 3.141592653589793
// #define mod 1000000007
#define P 1000000007
#define LL long long
#define pb push_back
#define fi first
#define se second
#define cl clear
#define si size
#define lb lower_bound
#define ub upper_bound
#define bug(x) cerr<<#x<<" : "<<x<<endl
#define mem(x,y) memset(x,0,sizeof(int)*(y))
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
LL ans;
map<LL,bool>have;
inline LL mul(LL a,LL b,LL p){
return a*b%p;
}
inline LL pow(LL a,LL n,LL p){
LL res=1;
while(n){
if(n&1)res=mul(res,a,p);
a=mul(a,a,p);n>>=1;
}
return res;
}
bool check(LL a,LL m,LL n,LL cnt){
LL x=pow(a,m,n),y=x;
for(int i=1;i<=cnt;i++){
x=mul(x,x,n);
if(x==1&&y!=1&&y!=n-1)return 1;
y=x;
}
return x!=1;
}
bool Miller_Rabin(LL n){
if(n==2)return 1;
if(n&1==0||n<=1)return 0;
LL m=n-1,cnt=0;
while(m&1==0)cnt++,m>>=1;
for(int i=1;i<=15;i++){
if(check(rand()%(n-1)+1,m,n,cnt))
return 0;
}
return 1;
}
LL rho(LL a,LL n,LL c){
LL i=1,k=2,x=a,y=x,d;
while(1){
x=(mul(x,x,n)+c)%n;
d=x>y?__gcd(x-y,n):__gcd(y-x,n);
if(d>1)return d;
if(x==y)return n;
if(i==k)y=x,k<<=1;
i++;
}
}
// std::vector<int> v;
void Pollard_rho(LL n){
if(n==1)return;
if(Miller_Rabin(n)){
if(!have[n])ans=ans/n*(n-1);
have[n]=1;
// v.pb(n);
return;
}
LL p=n;
while(p==n)p=rho(rand()%(n-1)+1,n,rand()%(n-1)+1);
Pollard_rho(p),Pollard_rho(n/p);
}
int phi[N],prime[N],num;
bool flag[N];
void pre(int n){
phi[1]=1;
for (int i=2;i<=n;i++){
if (!flag[i]){
prime[++num]=i;
phi[i]=i-1;
}
for (int j=1;j<=num&&prime[j]*i<=n;j++){
flag[i*prime[j]]=1;
if (i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}else phi[i*prime[j]]=phi[i]*phi[prime[j]];
}
}
}
LL eular(LL n){
if (n<N) return phi[n];
have.clear();
ans=n;
Pollard_rho(n);
return ans;
}
int a[150];
inline bool check(int ans){
for(int i=0;i<100;i++)
if (eular(i+ans)==a[i]) continue;
else return false;
return true;
}
bool solve(int pos){
if (Miller_Rabin(a[pos]+1)){
int ans=a[pos]+1-pos;
if (check(ans)) {
printf("YES\n%d\n",ans);
return 1;
}
}
for(int i=1;i<=num;i++){
if (a[pos]%(prime[i]-1)==0&&Miller_Rabin(a[pos]/(prime[i]-1)+1)){
LL ans=1ll*prime[i]*(a[pos]/(prime[i]-1)+1)-pos;
if (ans>150000000) continue;
if (check(ans)){
printf("YES\n%lld\n",ans);
return 1;
}
if (1ll*prime[i]*prime[i]>a[pos]*2) break;
}
}
puts("NO");
return 0;
}
int main()
{
srand(time(0));
pre(N-1);
int T; sc(T);
while(T--){
for(int i=0;i<100;i++) sc(a[i]);
int k=max_element(a,a+100)-a;
solve(k);
}
return 0;
}