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 的数(也就是n 或 2n)。假设与它配对的数 mod n = x。再选另一个mod n = 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; }