题目链接
题目大意:把(1)到(n)总共(n)个数两两分组,要求分组尽可能多并且每组的(gcd)都大于(1)。
做法大致就是先把所有的素数筛出来,然后先去除所有大于(lfloor frac{n}{2}
floor)的素数。对于剩下来的素数对于他所有的倍数且尚未匹配的进行任意匹配,若个数为奇数,则留下他的(2)倍用作后续匹配,最后会剩下一堆偶数,会算在(2)的倍数中,进行任意匹配即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int prime[maxn];
bool vis[maxn];
int ans[maxn << 1];
int cnt, num;
void init(){
for (int i = 2; i < maxn; i++){
if (!vis[i])prime[++cnt] = i;
for (int j = 1; j <= cnt && prime[j] * i < maxn; j++){
vis[prime[j] * i] = 1;
if (i % prime[j] == 0)break;
}
}
}
int main(){
init();
int t;cin>>t;
while(t--){
int n;
scanf("%d", &n);
num = 0;
for (int i = 1; i <= n; i++) vis[i] = false;
int mx = upper_bound(prime + 1, prime + cnt + 1, n / 2) - prime - 1;
for (int i = mx; i; i--){
int pp = prime[i];
for (int j = pp; j <= n; j += pp){
if (vis[j])continue;
if (j == pp * 2)continue;
ans[++num] = j;
vis[j] = true;
}
if (num & 1) ans[++num] = pp * 2, vis[pp * 2] = true;
}
printf("%d
", num >> 1);
for (int i = 1; i <= num; i += 2)
printf("%d %d
", ans[i], ans[i + 1]);
}
}