题意:有N个苹果,编号为1~N。现要将苹果组成若干对,每对苹果最小公约数不为1。求最多能分成多少对,输出各对的组成。
题解:先筛素数,然后搞。
首先我们怕的是乱选了两个数组成了公约数不为1的一对,但是这导致了总对数减少(这两个数分别被别的数需要,它们组成一对了不是最优解)。为了防止这种情况,我们要想办法让总对数不会减少。
我们发现2的倍数们非常碉炸,任意2个就能组成1对,所以我们先弄其他的数,最后再搞2的倍数。
我们发现一个质数x的1倍、2倍、3倍、……?倍中未使用的数组成的集合,也可以任意两两组合,但是如果在1~n之间,这个集合的元素个数是奇数,就会多一个。为了不造成多余的影响,我们把2*x作为多出来的一个,扔到2的倍数中去。这样,各种集合的多出来的一个,肯定能找到配对。把我们使用的数标记一下,防止搞其他质数的时候重复用一个数。
先搞完3到小于等于(N/2)的质数(大于N/2,它的倍数的集合就只有它自己了,没法玩),然后搞2的倍数,把之前扔进来的2*x们和其他2*y(y是合数)组成一个大集合,两两配对,最后再多出来一个也没办法了,这已经是最多的配对了。
解不唯一,我们这样搞肯定能找到最多的对数
//#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cmath>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
using namespace std;
#define ll long long
#define usll unsigned ll
#define mz(array) memset(array, 0, sizeof(array))
#define minf(array) memset(array, 0x3f, sizeof(array))
#define REP(i,n) for(i=0;i<(n);i++)
#define FOR(i,x,n) for(i=(x);i<=(n);i++)
#define RD(x) scanf("%d",&x)
#define RD2(x,y) scanf("%d%d",&x,&y)
#define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define WN(x) prllf("%d\n",x);
#define RE freopen("D.in","r",stdin)
#define WE freopen("1biao.out","w",stdout)
#define mp make_pair
#define pb push_back
const long N = 100001;
int prime[N],pn = 0;
bool isnp[N];
void shai() {
int i,j;
memset(prime,0,sizeof(prime));
memset(isnp,0,sizeof(isnp));
isnp[0]=1,isnp[1]=1;
pn=0;
for(i = 2 ; i < N ; i ++) {
if(! isnp[i])
prime[pn ++]=i;
//关键处1
for(j = 0 ; j < pn && i * prime[j] < N ; j ++) {
isnp[i * prime[j]] = 1;
if( !(i % prime[j] ) ) //关键处2
break;
}
}
}
int n;
vector<int>a,a2;
vector<pair<int,int> >v;
bool used[N];
int main() {
int i,j,k;
int l,r,mid;
int pre;
int ans;
shai();
while(scanf("%d",&n)!=EOF) {
ans=0;
v.clear();
a2.clear();
memset(used,0,sizeof(used));
for(i=1; prime[i]<=n/2; i++) {
a.clear();
a.pb(prime[i]);
for(j=3*prime[i]; j<=n; j+=prime[i]) if(!used[j]) a.pb(j);
if(a.size()%2==0) a2.pb(2*prime[i]);
else a.pb(2*prime[i]);
int maxj=a.size();
for(j=0; j+1<maxj; j+=2) {
v.pb(mp(a[j],a[j+1]));
used[a[j]]=1;
used[a[j+1]]=1;
}
}
if(n>=2)a2.pb(2);
if(n>=4)a2.pb(4);
for(i=4; i+i<=n; i++) {
if(!used[i+i] && isnp[i]) a2.pb(i+i);
}
int maxi=a2.size();
for(i=0; i+1<maxi; i+=2) v.pb(mp(a2[i],a2[i+1]));
printf("%d\n",v.size());
maxi=v.size();
REP(i,maxi) printf("%d %d\n",v[i].first,v[i].second);
}
return 0;
}