题目链接:ZOJ (pintia.cn)
Sample Input
3 1 4 6
Sample Output
0 1 2 4 2 2 4 3 6
题目大意:给出1-n共n个数,对n个数进行分组,组内元素的最大公因数不能是1,求最多能构成多少组,并输出方案
思路:如何构造两两配对且gcd不为1的数,我们应该联想到质数,我们从大到小统计每个质数遇到质数s,看s到n有几个未使用的s的倍数cnt,如果 cnt为奇数,则从3*s开始存,最后全部分给2的倍数。
#include<bits/stdc++.h>
#define int long long
#define lmw ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N=1e5+10;
int a[N],p[N],ip[N],s[N];
vector<int>f[N];
void unit(){
int cnt=0;
memset(ip,1,sizeof(ip));
p[1]=p[0]=0;
for(int i=2;i<=N;i++){
if(ip[i]){
p[++cnt]=i;
}
for(int j=1;j<=cnt&&i*p[j]<=N;j++){
ip[i*p[j]]=0;
if(!i%p[j]) break;
}
}
}
signed main(){
unit();
lmw;
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int op=0;
if(n<=3){
cout<<"0\n";
continue;
}
else{
for(int i=n;i>=2;i--){
if(!ip[i]) continue;
else {
int cnt=1,num=0;
s[i]=1;
for(int j=i*2;j<=n;j+=i){
if(!s[j]) cnt++;
}
cnt&1?num=3*i:num=2*i;
f[i].push_back(i);
if(cnt>1) op++;
for(int j=num;j<=n;j+=i){
if(!s[j]){
f[i].push_back(j);
s[j]=1;
op++;
}
}
}
}
cout<<op/2;
for(int i=2;i<=n;i++){
if(f[i].size()<=1) continue;
int len=f[i].size();
for(int j=0;j<len;j+=2){
cout<<" "<<f[i][j]<<" "<<f[i][j+1];
}
}
}
cout<<"\n";
memset(s,0,sizeof(s));
for(int i=2;i<=n;i++){
f[i].clear();
}
}
}