[思维] codeforces 665D. Simple Subset

题意:
给一个n个正整数序列 a ,要找一个最大的子序列,使子序列里任意两个元素 aiaj1<=i<j<=n)ai+aj 都是素数,要输出这个子序列的大小和子序列的元素。
1<=n<=1000
1<=a[i]<=106
题解:
设一个满足要求的子序列为 A
如果 |A|<3 ,那么只需用 n2 的暴力即可。
如果 |A|>=3 ,设 abc A 中任意三个不同位置的数,那么 abc 必有2个数奇偶性相同。
ab 的奇偶性相同,那么有下面两种情况:
ab 为偶数,那么 a+b 为偶数。由于 ab 都不为0,显然 a+b 不是素数,所以这种情况不可能出现。
ab 为奇数,那么 a+b 为偶数。当 a=b=1 时, a+b 为素数,否则不为素数。

结论:如果 |A|>=3 ,那么 |A| 至少含有2个1,且即最多有一个数大于1。

所以首先判断原数列 a 有几个1。
如果1的个数小于2,那么 |A|<3 ,采用第一种做法暴力。
如果1的个数大于等于2,那么把所有1都加入答案,并且再判断是否存在一个数 x ,使得 x+1 为素数。根据前面的结论,最多可以加入一个大于1的数。

#include<bits/stdc++.h>
using namespace std;
const int N = 2000005;
int a[1005];
bool prime[N];
void init(){
    for(int i = 0; i < N; ++i) prime[i] = 1;
    for(int i = 2; i < N; ++i){
        if(!prime[i]) continue;
        for(int k = 2; i*k < N; ++k){
            prime[i*k] = 0;
        }
    }
}
int main(){
    init();
    int n;
    cin >> n;
    for(int i = 0; i < n; ++i) cin >> a[i];
    sort(a, a+n);
    int cot = 0;
    for(int i = 0; i < n; ++i) if(a[i] == 1) cot += 1;
    if(cot < 2){
        int flag = 0;
        for(int i = 0; i < n && !flag; ++i){
            for(int j = i+1; j < n && !flag; ++j){
                if(prime[a[i]+a[j]]){
                    printf("2\n%d %d", a[i], a[j]);
                    flag = 1;
                }
            }
        }
        if(!flag) printf("1\n%d", a[0]);
    }
    else{
        int flag = 0;
        for(int i = 0; i < n && !flag; ++i){
            if(a[i] != 1 && prime[a[i]+1]){
                printf("%d\n%d ", cot+1, a[i]);
                flag = 1;
            }
        }
        if(!flag) printf("%d\n", cot);
        for(int i = 0; i < cot; ++i) printf("1 ");
    }
    cout << endl;
}

你可能感兴趣的:(数学,codeforces)