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 的数各被选中一次

证:

先随便选一个mod n = 0 的数(也就是或 2n)。假设与它配对的数 mod x。再选另一个mod 的数。再把与新选的数配对的数抛弃掉,选一个与之同余的......。直到某一次被抛弃掉的数,就是另一个 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;
}

 

posted on 2020-09-10 16:24  Willems  阅读(190)  评论(0编辑  收藏  举报

导航