题意
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;
}