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 @ 2023-01-23 13:51  empty_y  阅读(129)  评论(0)    收藏  举报