• 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;
    }
  • 相关阅读:
    CSPS模拟 49
    StrGame
    CSPS模拟 48
    [没有证明]原根求法
    CSPS模拟 47
    CSPS模拟 46
    CSPS模拟 45 乔迁之喜
    CSPS模拟 44
    平衡二叉树
    go语言学习--指针数组和数组指针
  • 原文地址:https://www.cnblogs.com/Willems/p/13646487.html
Copyright © 2020-2023  润新知