这道题好像一开始想到了差不多的做法orz?后来都不大敢相信就是这么做的……有点瞎搞。
后来看了CF的官方题解,感觉还是挺有道理的。首先对于1和大于n/2的质数肯定是不行的,我们直接忽略。然后,对于每一个质数的倍数,我们肯定是把他们组合在一起更优。如果这些数有奇数个,那我们就把质数的2倍挑出来(因为2倍是最容易组合的!)
如果有偶数个就直接组合。
最后你肯定剩下的全都是偶数,那么随便组合就行啦!
直接用两个栈模拟即可。
看一下代码。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<set> #include<queue> #define pr pair<int,int> #define mp make_pair #define fi first #define sc second #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(‘\n‘) using namespace std; typedef long long ll; const int M = 200005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) { if(ch == ‘-‘) op = -1; ch = getchar(); } while(ch >= ‘0‘ && ch <= ‘9‘) { ans *= 10; ans += ch - ‘0‘; ch = getchar(); } return ans * op; } int n,p[M],stack[M],tot,cur,sta[M],cnt,now; bool np[M],vis[M]; pr ans[M]; void euler() { np[1] = 1; rep(i,2,n) { if(!np[i]) p[++tot] = i; for(int j = 1;i * p[j] <= n;j++) { np[i*p[j]] = 1; if(!(i%p[j])) break; } } } int main() { n = read(); euler(); rep(i,2,tot) { if(p[i] > n>>1) break; rep(j,1,n/p[i]) if(j != 2 && !vis[p[i] * j]) sta[++cur] = p[i] * j,vis[p[i] * j] = 1; if(cur&1) { sta[++cur] = p[i] << 1,vis[p[i] << 1] = 1; while(cur) ans[++cnt].fi = sta[cur--],ans[cnt].sc = sta[cur--]; } else { stack[++now] = p[i] << 1,vis[p[i] << 1] = 1; while(cur) ans[++cnt].fi = sta[cur--],ans[cnt].sc = sta[cur--]; } } rep(j,1,n>>1) if(!vis[j<<1]) stack[++now] = j << 1; if(now&1) now--; while(now) ans[++cnt].fi = stack[now--],ans[cnt].sc = stack[now--]; printf("%d\n",cnt); rep(i,1,cnt) printf("%d %d\n",ans[i].fi,ans[i].sc); return 0; }
原文地址:https://www.cnblogs.com/captain1/p/9781303.html
时间: 2024-10-04 23:06:48