【2020牛客多校第四場 H題】Harder Gcd Problem
阿新 • • 發佈:2020-07-21
題意
給出 n 個數字1 2 3 .... n ,讓構造出兩個集合 A,B ,滿足以下條件:
- A ∩ B == ∅ and | A | == | B | == m
- \(gcd(A_i,B_i) > 1\)
思路
按照每個數字的最小質因子分組。
2:
3:
5:
7:
...
初始一直想的是從 2組開始,組中每兩個作為一對輸出,如果有奇數個數字,那麼將最後一個數字除完所有的 2 ,將其放到次小質因子組中去。就這樣一直遍歷。然後直接找出了反例。。。
然後就想著改進,但是想出的方法都給人一種不完美的感覺。
題解
從 3 開始進行,如果當前組的數字個數為奇數,那麼從 2 組中判斷是否有最小數字的 2 倍,如果有那麼這倆數字作為一對,其他相鄰的作為一對。
就是把 2組中的數字當做備選,最後 2 組再自行匹配。
程式碼
#include <bits/stdc++.h> #define emplace_back push_back #define pb push_back using namespace std; typedef long long ll; const int mod = 1e9 + 7; const int inf = 0x3f3f3f3f; const int N = 1e6 + 10; int vis[N],pri[N],tot; void solve(int n) { for(int i=2; i<=n; i++) { if(!vis[i]) pri[++tot]=i; for(int j=1; j<=tot; j++) { if(i*pri[j]>n) break; vis[i*pri[j]]=pri[j];//紀錄最小的素因子 if(i%pri[j]==0) break; } } } vector<int>vec[N]; vector<pair<int,int> >ans; int sign[N]; int main() { solve(200005); int T; scanf("%d",&T); while(T--) { int n; scanf("%d",&n); for(int i=1; i<=n; i++) vec[i].clear(); ans.clear(); for(int i=2; i<=n; i++) { if(vis[i]==0) vis[i]=i; sign[i]=0; vec[vis[i]].pb(i); } for(int i=3;i<=n;i++) { if(vec[i].size()%2){ for(int j=1;j+1<vec[i].size();j+=2) ans.pb(make_pair(vec[i][j],vec[i][j+1])); if(sign[vec[i][0]*2]==0&&2*vec[i][0]<=n){ ans.pb(make_pair(vec[i][0],vec[i][0]*2)); sign[vec[i][0]*2]=1; } } else{ for(int j=0;j+1<vec[i].size();j+=2){ ans.pb(make_pair(vec[i][j],vec[i][j+1])); } } } int pre=0; for(int v:vec[2]){ if(sign[v]==0){ if(pre==0) pre=v; else { ans.pb(make_pair(pre,v)); pre=0; } } } printf("%d\n",ans.size()); for(auto now:ans){ printf("%d %d\n",now.first,now.second); } } return 0; }