2020牛客暑期多校訓練營(第四場)H-Harder Gcd Problem(貪心)
阿新 • • 發佈:2020-07-20
題目連結
題目大意:把\(1\)到\(n\)總共\(n\)個數兩兩分組,要求分組儘可能多並且每組的\(\gcd\)都大於\(1\)。
做法大致就是先把所有的素數篩出來,然後先去除所有大於\(\lfloor \frac{n}{2} \rfloor\)的素數。對於剩下來的素數對於他所有的倍數且尚未匹配的進行任意匹配,若個數為奇數,則留下他的\(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\n", num >> 1); for (int i = 1; i <= num; i += 2) printf("%d %d\n", ans[i], ans[i + 1]); } }