牛客多校第四场 H 贪心+埃氏筛

Harder Gcd Problem.

题意

1到n个数,取两个不互质的数配对,求最多能配几对。

分析

根据题意易得偶数肯定能互相配对,但是像10,14这种偶数也能跟5,7这种素数配对,所有要用贪心的思想,如果单纯的让偶数和偶数配对,那么素数就用不到了,结果可能就不是最优的,如果让把一些偶数取出来去和素数配对,结果就是最大的。
所以先让素质去找他的倍数配对,用过的数用vis标记一下。

比如n=10 的时候,1到10个数。
如果单纯偶数和偶数配: 2和4 , 6和8, 5和10 ,这样3就没有用上,而且才3对,不是最优解
但是如果让除了2的素数优先: 3和6 , 5和10 ,2和4 , 6和8 ,这样就有4对,因为我们让3和5都参与到了配对。

如果一个素数x和他的倍数的数量是奇数,那么2x不用配对,因为2x肯定数偶数,可以留着最后偶数两两配对,如果一个素数x和他的倍数的数量是奇数,那么就两两配对,配对的数量用ans记录。

最后把没有用过的偶数两两配对。

#include<bits/stdc++.h>
#define ll long long
#define T int t;scanf("%d", &t);while(t--)
using namespace std;
int dx[]={0,0,-1,1};
int dy[]={1,-1,0,0};
const ll mod = 1e9+7;
const int maxn = 2e5+5;
int a[maxn];		//埃氏筛
int n;
int vis[maxn];
int main(){
    T{
        int n;
        scanf("%d", &n);
        vector<pair<int ,int > > ans;		//配对
        memset(vis,0,sizeof(vis));	//记录用过没
        memset(a,0,sizeof(a));	
        //注意循环条件,i*2大于n的质数肯定没有数与他配对	
        for(int i = 2; i * 2 <= n; i++){	
            if(a[i]) continue;	
            int cnt = 0;
            vector<int> s;
            for(int j = i; j <= n; j+=i){
                a[j] = 1;	//筛掉合数
                if(vis[j]==0 && i != 2){  //2的倍数留到最后处理
                    cnt ++;		
                    s.push_back(j);	 //把质数的倍数都放入vector用于配对
                }
            }
            if(i == 2) continue;		//偶数留到最后处理
            int k = 0;
            if(cnt % 2){				//如果不互质的个数是奇数个
            	ans.push_back({s[0],s[2]});
        		vis[s[0]] = 1;		//s[1]不用于本次配对
        		vis[s[2]] = 1;
        		k = 3;
        	}
        	for( k = k; k < s.size(); k += 2){
        		ans.push_back({s[k],s[k+1]});
        		vis[s[k]] = 1;
        		vis[s[k+1]] = 1;
        	}
        }
        int f = -1;
        //最后所有没用过的偶数两两配对
        for(int i = 2; i <= n; i += 2){	
            if(vis[i]==0){
                if(f == -1){
                    f = i;
                }else{
                    ans.push_back({f,i});
                    f = -1; 	
                }
            }
        }
        printf("%d\n", ans.size());
        for(int i = 0; i < ans.size(); i++) 
        	printf("%d %d\n", ans[i].first, ans[i].second);
    }
 
    return 0;
}

猜你喜欢

转载自blog.csdn.net/HHeyanjie/article/details/107517169