1. 程式人生 > 實用技巧 >D. Game of Pairs (構造,思維)

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的數(也就是n2n)。假設與它配對的數modn=x。再選另一個

modn=x的數。再把與新選的數配對的數拋棄掉,選一個與之同餘的......。直到某一次被拋棄掉的數,就是另一個modn = 0 的數,那麼當前所選的數就形成了一個閉環。同理,剩下的數也一定是若干個閉環,每個環相互獨立,我們各個擊破即可。

#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;
}