D. Game of Pairs (構造,思維)
題目:傳送門
題意
有兩個人 First 和 Second 在玩遊戲,首先,給出一個 n,First 會將 1,2,....2*n 這 2*n 個數分成 n 組,而 Second 要在這 n 組數中,每組選一個數,若 Second 選的 n 個數的和是 2 * n 的倍數,則 Second 贏,否則,Frist 贏。
現在給你一個 n,問你你是要選 First 還是選 Second;
若你選 First,那你需要輸出一個長度為 2*n 的序列, ans[ i ] 表示 i 這個數屬於哪個組,且你的分組必須使得 Second 不能贏。
若你選 Second,那會輸入一個 2 * n 的序列,表示 First 的分組,你需要輸出 n 個不同組的數,表示你選則的數,且這些數的和必須是 2 * n 的倍數。
1 <= n <= 5e5
思路
精彩講解
首先,這題需要分兩種情況考慮
1.若 n 是偶數,則選先手必勝
此時可以讓 (i, i + n) 一組,這樣,Second 選擇的 n 個數,取餘 n 分別等於 1, 2, 3, .. n - 1,那麼他們的總和就是 s = n * (n - 1) / 2,設 n = 2 * m, 則 s = m * (2 * m - 1),由於 2 * m - 1 是奇數,所以,s 不可能是 n 的倍數,就更加不可能是 2n 的倍數了。
2.若 n 是奇數,則後手必勝
結論1:首先,若可以選擇出 n 個數,使得它們的和是 n 的倍數,則一定存在一種策略,選擇出 n 個數,使得它們的和是 2n 的倍數,此時它們的和在 mod n 意義下就是 0 + 1 + 2 +... + (n - 1) = n * (n - 1) / 2,一定是 n 的倍數。
證:
首先, 1 + 2 + ... + 2*n = 2*n * (2*n + 1) / 2 = n * (2 * n + 1),所以 n * (2 * n + 1) % (2 * n) = n,也就是所有數的和 % 2n = n。
那如果我們選擇出的 n 個數的和 % 2n = n,那其他的 n 個數的和 % 2n 就會等於 0,所以無論如何,一定可以選出 n 個數,使得它們的和 % 2n = 0;
結論2:一定存在一種方案,使得 mod n = 0, 1, 2 .... n - 1 的數各被選中一次
證:
先隨便選一個modn = 0的數(也就是n或2n)。假設與它配對的數modn=x。再選另一個
#include <bits/stdc++.h> #define LL long long #define ULL unsigned long long #define UI unsigned int #define mem(i, j) memset(i, j, sizeof(i)) #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define pb push_back #define make make_pair #define INF 0x3f3f3f3f #define inf LLONG_MAX #define PI acos(-1) #define fir first #define sec second #define lb(x) ((x) & (-(x))) #define dbg(x) cout<<#x<<" = "<<x<<endl; using namespace std; const int N = 1e6 + 5; int n, x, vis[N], pre[N]; vector < int > G[N]; vector < int > Q[2]; void dfs(int u, int x) { Q[x].pb(u); vis[u] = 1; for(auto v : G[u]) if(!vis[v]) dfs(v, x ^ 1); } void solve() { cin >> n; if(n % 2 == 0) { cout << "First" << endl; rep(i, 0, (2 * n) - 1) { cout << (i % n) + 1 << " "; } cout << endl; cin >> x; return ; } cout << "Second" << endl; rep(i, 1, 2 * n) { cin >> x; if(!pre[x]) pre[x] = i; else G[pre[x]].pb(i), G[i].pb(pre[x]); } rep(i, 1, n) G[i].pb(i + n), G[i + n].pb(i); rep(i, 1, 2 * n) if(!vis[i]) dfs(i, 0); LL s = 0; for(auto v : Q[0]) s += v; if(s % (2 * n) == 0) { for(auto v : Q[0]) cout << v << " "; } else for(auto v : Q[1]) cout << v << " "; cout << endl; cin >> x; } int main() { // int _; scanf("%d", &_); // while(_--) solve(); solve(); return 0; }