题解:CF2029E Common Generator
前言
好题,实在是一道很好的数学题。
本文主要参考了 这篇题解。
思路
看到这种题,特别是和因数相关,就可以往质数这一块多想想。
下面要证明一些定理。
引理 1:对于合数来说,
2 永远是满足条件的生成器。证明:采用归纳法。
假设当前数为x ,小于x 的合数都满足条件,那么可以分两种情况:
- 对于偶合数,有:
2 \mid x ,那显然也有2 \mid (x-2) ,因此可以从x-2 转移过来。对于奇合数,
x 也一定可以表示成x=pq 的形式(其中p 为最小的质因子)。因为
x 为合数,所以q>1 (根据因数定理可知)。又因为
x 不为偶数,所以不含有偶数因子,那么p \ge 3 。所以,(p-1)q 也一定是一个合数。根据前置的条件,(p-1)q 可以被表示,而p 是质数,所以pq 即x 可以表示为(p-1)q + p 。因此能被表示。得证。
考虑完了合数的情况,再考虑一下质数。
引理 2:质数只能由本身来生成。
证明:反证法。
如果一个质数p 可以由q 生成而来(q<p ),那么一定有:p=q+d ,其中d \mid q 并且d > 1 。因为
q=n \times d ,所以:p = q + d = (n+1)d 。$\therefore$ $p$ 是一个合数,矛盾。 得证。
到这里就有一个整体的思路了。
- 序列中没有质数。根据 引理 1,直接输出
2 即可。 - 序列中有不同的质数。根据 引理 2,不管选择哪一个都不能满足所有的数,因此无解。
- 序列中有且只有一个质数。还要再讨论一下。
发现只能选这个质数,于是探讨一下选它满不满足其他的合数。
引理 3:对于偶合数
p ,质数q 能表示它必须满足2q \le p 。证明:考虑是否为充分必要条件。
充分性:若
2q \le p ,根据 引理 2 可知,q 只能一步到达2q 。因为2|2q ,所以2|(p-2q) 。因此后面只要全用2 就好了。必要性:若
2q > p ,因为q 只有先到2q ,而此时已经超过了p ,后面再操作只会变大,距离p 越来越远,不可能表示出q 。因此,该条件是充分必要条件,得证。
接着,考虑一下奇数的情况。
引理 4:对于奇合数
p ,质数q 能表示它必须满足2q \le p - low_p 。其中low_p 表示p 的最小质因子。证明:还是考虑充分必要条件。
充分性:若
2q \le p-low_p ,根据 引理 2 可知,q 只能一步到达2q 。因为p 为奇数,所以low_p 也为奇数,所以p - low_p 为偶数。根据 引理 3 可知是合法的。必要性:若
2q > p-low_p ,因为q 只有先到2q ,可知此时2q \ne p ,因为奇偶性都不同。考虑能否到达p 。$\ \ \ \ \ \ \ \ \ \ \ \ \ $ 因此此时不可能到达 $p$。 所以该条件为充分必要条件,得证。
因此,只有一个质数的情况利用 引理3 以及 引理4 判断就好了。
代码
#include<iostream>
using namespace std;
int t,n;
const int N=5e5+10;
bool v[N];
int p[N],cnt;
int num[N];
void prime(){
v[1]=1;
for(int i=2;i<N;i++){
if(!v[i]){
p[++cnt]=i;
}
for(int j=1;j<=cnt&&i*p[j]<N;j++){
int next=i*p[j];
v[next]=1;
if(next&1){
num[next]=next-p[j];
}else{
num[next]=next;
}
if(i%p[j]==0){
break;
}
}
}
}
int a[N];
int main(){
prime();
cin>>t;
while(t--){
scanf("%d",&n);
int x=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
if(x==-1){
continue;
}
if(!v[a[i]]){
if(!x){
x=a[i];
}else{
x=-1;
}
}
}
if(x==-1){
puts("-1");
}else if(!x){
puts("2");
}else{
for(int i=1;i<=n;i++){
if(a[i]!=x&&num[a[i]]<2*x){
x=-1;
break;
}
}
cout<<x<<endl;
}
}
}