题目概述
定义好图当且仅当 \(1\) 和 \(n\) 不连通而且没有重边以及自环。
现在给出 \(n\) 个点和 \(m\) 条无向边,然后小 \(A\) 先手,可以选择两个点进行连边,小 \(B\) 后手。
请问先手是否有必胜策略,输当且仅当无法连边使得他是好图。
分析
博弈论好题。
一般先考虑什么时候输。
只剩下两个连通块,且每个连通块都是完全图。
那么现在操作的人一定输。
也就是说我们可以假设最后剩下的两个连通块中其中一个的点的个数为 \(x\),那么第二个连通块的就是 \((n-x)\) 个点。
也就是操作数就是:\(\frac{x(x+1)}2 +\frac{(n-x)(n-x+1)}{2}-m\)。
于是我们化简:
\[\begin{align}
\frac{x^2+x}{2}+\frac{(n-x)^2+(n-x)}{2}-m\\
=\frac{x^2+x}{2}+\frac{n^2+x^2-2nx+n-x}{2}-m\\
=\frac{n^2+n}{2}+\frac{2x^2-2nx}{2}-m\\
=\frac{n^2+n}{2}-x(n-x)-m
\end{align}
\]
显然考虑奇偶性。
当 \(n\) 为奇数的时候,那么 \(x(n-x)\) 一定是偶数,那么只需要判断前面的奇偶性即可。
当 \(n\) 为偶数的时候,考虑一开始含 \(1,n\) 的两个连通块
-
两者奇偶性相同,那么一定剩下偶数个有奇数个点的连通块,如果先手想要改变,那么后手也可以直接连奇数的连通块即可,令 \(x\) 为含 \(1\) 的连通块的大小。
-
否则,显然一定剩下奇数个有奇数个点的连通块,显然先手赢。
代码
时间复杂度 \(\mathcal{O}(n\alpha (n))\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <algorithm>
#include <vector>
#define F First
#define S Second
#define int long long
#define N 100005
using namespace std;
int fa[N],n,T,m,sz[N];
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);
}
signed main(){cin >> T;for (;T--;) {scanf("%lld%lld",&n,&m);for (int i = 1;i <= n;i ++) fa[i] = i,sz[i] = 1;for (int i = 1;i <= m;i ++) {int u,v;scanf("%lld%lld",&u,&v);int x = find(u),y = find(v);if (x != y) fa[x] = y,sz[y] += sz[x];}if (n & 1) {if ((n * (n - 1) / 2 - m) & 1) puts("First");else puts("Second");}else {int now = n * (n - 1) / 2 - m;if ((sz[find(1)] & 1) != (sz[find(n)] & 1)) puts("First");else puts((now - sz[find(1)] * sz[find(n)]) & 1 ? "First" : "Second");}}return 0;
}