2023牛客寒假基础训练营3 I(哥德巴赫猜想)

I.灵魂碎片的收集

题目大意:

定义S(n) 表示为所有小于n的约数之和。例如S(10) = 1 + 2 + 5 = 8
现在给定一个数x,求是否有一个n满足S(n) = x。
(题目保证如果x为偶数,那么x-1或者x-3其中至少有一个为质数,若x为奇数,则没有限制)


解题思路:

哥德巴赫猜想:

  1. 任何一个大于6的偶数都可以表示成两个素数之和
  2. 任何一个大于9的奇数都可以表示成三个素数之和

当我们看到题目中的数据保证时第一时间就会考虑到以x为奇数\偶数来分类。

  1. 如果x为偶数:
  • 我们考虑x-1或者x-3为质数会对答案有什么贡献,如果为质数,那么他所能提供的约数只有1和质数本身
  • 所以如果当x-1为质数时,如果这时候的约数为1和x-1,那他的和刚好就是x,所以此时我们构造n为(x-1)^2,那么小于n的约数就为[1、x-1]
  • 同样如果x-3为质数时,他所能提供的约数为1和x-3,与x相比还差2,所以我们考虑给它补一个约数2,所以我们构造n为2*(x-3),此时小于n的约数为[1、2、x-3]
  1. 如果x为奇数:
  • 我们会发现如果去构造奇数是很难的,所以我们考虑将问题转化为偶数的情况下,此时我们考虑x-1的情况,因为x-1为偶数,那么根据哥德巴赫猜想,在大于6的情况下可以将其表示为两个素数之和,也就是说n的约数可以由[a,b]两个质数构成,那么他们的和就是a+b = x-1,再加上1这个约数,刚好满足约数之和为x,所以我们就考虑构造n = a X b(a,b为两个大于x的不同质数)
  1. 特殊情况:
  • 因为我们用到了哥德巴赫猜想,所以对于x-1小于等于6的情况都需要进行特判,自己写写就出来了

代码实现:

# include<bits/stdc++.h>
using namespace std;
const int N = 5e6+10;
# define int long long
vector<int> e[N];
int a[N];
int f[N],sz[N];
int primes[N];//质数
int vis[N],minp[N],cnt;//minp 对x的最小质数
void init()
{
for(int i = 2; i < N; i ++ )
{
if(!vis[i]) primes[cnt ++ ] = i, minp[i] = i;
for(int j = 0; primes[j] * i < N; j ++ )
{
vis[primes[j] * i] = true;
minp[primes[j] * i] = primes[j];
if(i % primes[j] == 0) break;
}
}
}
signed main(){
init();
int tt;
cin>>tt;
while(tt--){
int n;
cin>>n;
if(n == 1) {
cout<<3<<endl;
continue;
}
if(n == 3) {
cout<<4<<endl;
continue;
}
if(n == 5||n==2){
cout<<-1<<endl;
continue;
}
if(n==6){
cout<<6<<endl;
continue;
}
if(n==7){
cout<<8<<endl;
continue;
}
if(!(n&1)){
if(!vis[n-1]) cout<<(n-1)*1ll*(n-1)<<endl;
else if(!vis[n-3]) cout<<2ll*(n-3)<<endl;
else cout<<-1<<endl;
}
else{
bool ok = false;
for(int i = 0;i < cnt;++i){
if(primes[i]<n-1&&(!vis[n-1-primes[i]])&&(n-1-primes[i]!=primes[i])){
int ans = primes[i]*(n-1-primes[i]);
cout<<ans<<endl;
ok = 1;
break;
}
}
if(!ok) cout<<-1<<endl;
}
}
return 0;
}
posted @   empty_y  阅读(110)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示