专栏文章

题解:CF2029E Common Generator

CF2029E题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqde14a
此快照首次捕获于
2025/12/04 02:58
3 个月前
此快照最后确认于
2025/12/04 02:58
3 个月前
查看原文

前言

好题,实在是一道很好的数学题。
本文主要参考了 这篇题解

思路

看到这种题,特别是和因数相关,就可以往质数这一块多想想。
下面要证明一些定理。
引理 1:对于合数来说,22 永远是满足条件的生成器。
证明:采用归纳法。
假设当前数为 xx,小于 xx 的合数都满足条件,那么可以分两种情况:
  • 对于偶合数,有:2x2 \mid x,那显然也有 2(x2)2 \mid (x-2),因此可以从 x2x-2 转移过来。
  • 对于奇合数,xx 也一定可以表示成 x=pqx=pq 的形式(其中 pp 为最小的质因子)。
    因为 xx 为合数,所以 q>1q>1(根据因数定理可知)。
    又因为 xx 不为偶数,所以不含有偶数因子,那么 p3p \ge 3。所以,(p1)q(p-1)q 也一定是一个合数。根据前置的条件,(p1)q(p-1)q 可以被表示,而 pp 是质数,所以 pqpqxx 可以表示为 (p1)q+p(p-1)q + p。因此能被表示。
得证。
考虑完了合数的情况,再考虑一下质数。
引理 2:质数只能由本身来生成。
证明:反证法。
如果一个质数 pp 可以由 qq 生成而来(q<pq<p),那么一定有:p=q+dp=q+d,其中 dqd \mid q 并且 d>1d > 1
因为 q=n×dq=n \times d,所以:p=q+d=(n+1)dp = q + d = (n+1)d
\because n+12n+1 \ge 2d2d \ge 2
\therefore pp 是一个合数,矛盾。
得证。
到这里就有一个整体的思路了。
  • 序列中没有质数。根据 引理 1,直接输出 22 即可。
  • 序列中有不同的质数。根据 引理 2,不管选择哪一个都不能满足所有的数,因此无解。
  • 序列中有且只有一个质数。还要再讨论一下。
发现只能选这个质数,于是探讨一下选它满不满足其他的合数。
引理 3:对于偶合数 pp,质数 qq 能表示它必须满足 2qp2q \le p
证明:考虑是否为充分必要条件。
充分性:若 2qp2q \le p,根据 引理 2 可知,qq 只能一步到达 2q2q。因为 22q2|2q,所以2(p2q)2|(p-2q)。因此后面只要全用 22 就好了。
必要性:若 2q>p2q > p,因为 qq 只有先到 2q2q,而此时已经超过了 pp,后面再操作只会变大,距离 pp 越来越远,不可能表示出 qq
因此,该条件是充分必要条件,得证。
接着,考虑一下奇数的情况。
引理 4:对于奇合数 pp,质数 qq 能表示它必须满足 2qplowp2q \le p - low_p。其中 lowplow_p 表示 pp 的最小质因子。
证明:还是考虑充分必要条件。
充分性:若 2qplowp2q \le p-low_p,根据 引理 2 可知,qq 只能一步到达 2q2q。因为 pp 为奇数,所以 lowplow_p 也为奇数,所以 plowpp - low_p 为偶数。根据 引理 3 可知是合法的。
必要性:若 2q>plowp2q > p-low_p,因为 qq 只有先到 2q2q,可知此时 2qp2q \ne p,因为奇偶性都不同。考虑能否到达 pp
             \ \ \ \ \ \ \ \ \ \ \ \ \ 假设一个数 xx 可以一步到达 qq,则跨越的数值 d=qxd=q-x 一定为 xx 以及 qq 的因数。可知此时 dlowpd \ge low_p,所以当 xplowpx \le p-low_p 才满足条件。可是2q>plowp2q > p-low_p,矛盾。
             \ \ \ \ \ \ \ \ \ \ \ \ \ 因此此时不可能到达 pp
所以该条件为充分必要条件,得证。
因此,只有一个质数的情况利用 引理3 以及 引理4 判断就好了。

代码

CPP
#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;
		}
	}
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...