题意已经有很多大佬说过了,我用集合整了一个好理解但是慢的写法(毕竟2e5.....)
先求出list[x] 表示 x的最大质数因子是list[x],可以筛一波
然后扔进集合,从大质数因子开始遍历。如果集合x大小是奇数(最大质因子是x的数字有奇数个),那就把其中的偶数扔进集合2.最后把集合2判断完就行(逃
#include<iostream>
#include<set>
#include<vector>
using namespace std;
const int Maxn = 2e5 + 11;
const int maxn = 2e5 + 11;
int prime[Maxn];
int Mark[Maxn + 1];
vector<int>chal;
int pr() {//筛素数不用看
int p = 0;
Mark[0] = 1;
Mark[1] = 1;
for (int i = 2; i < Maxn; i++) {
if (Mark[i] == 0) {
prime[p++] = i;
}
for (int j = 0; j < p && prime[j] * i < Maxn; j++) {
Mark[i * prime[j]] = 1;
if (i % prime[j] == 0) {
break;
}
}
}
return p;
}
int list[maxn];
set<int>ins[maxn];
set<int>::iterator it;
int main() {
pr();
for(int i=0; i<maxn; i++) {
if(!Mark[i]) list[i] = i;//质数的list就是他自己
}
for(int i=2; i<maxn; i++) {//求出list
for(int j=2; j*i<maxn; j++) {
list[i*j] = max(list[i],max(list[j],list[i*j]));
}
}
int t;
scanf("%d",&t);
while(t--) {
int n;
scanf("%d",&n);
for(int i=2; i<=n; i++) ins[i].clear();
chal.clear();
for(int i=2; i<=n; i++) {
if(i>(n/2) && list[i] == i) continue;//扔掉没用的答案
ins[list[i]].insert(i);
}
for(int i=n; i>2; i--) {
if(ins[i].size() == 0) continue;
if(ins[i].size() % 2 == 0) { //全配对
int j = 0;
for(it = ins[i].begin(); it != ins[i].end(); it++) {
int a = *it;
chal.push_back(a);
}
}
else { //扔出去一个偶数
int cns = i*2;
it = ins[i].find(cns);
ins[i].erase(it);
ins[2].insert(cns);
int j=0;
for(it = ins[i].begin(); it != ins[i].end(); it++) {
int a = *it;
chal.push_back(a);
}
}
}
if(ins[2].size() & 1) {
ins[2].erase(ins[2].begin());
}
for(it = ins[2].begin(); it != ins[2].end(); it++) {
int a = *it;
chal.push_back(a);
}
printf("%d\n",chal.size()/2);//输出答案
for(int i=0;i<chal.size();i+=2){
printf("%d %d\n",chal[i],chal[i+1]);
}
}
return 0;
}

京公网安备 11010502036488号