题目大意
两个人玩游戏,有n (1<=n<=10^5 )个点,每个点的坐标为 (xi,yi)( 0<=xi,yi<=10^9 ),起点为sx,sy ( 0<=sx,xy<=10^9 ),起始时sum=0,轮流操作,每次选一个点,sum将增加该点与上一个点的距离,n个点全部选完之后,如果sum为偶数则先手获胜,否则后手获胜,选择先手还是后手,怎么玩能保证一定是胜利的。
思路
设第i个点的坐标为(xi,yi).则最终的sum=(+)%2,只关系其奇偶性,直接去平方(偶数的平方仍是偶数,奇数亦然),得
,展开会发现中间部分的数会被消掉只剩下起点和终点,所以最终答案的奇偶只看起点和终点的性是否相同,若相同则先手获胜,若不同则后手获胜。
记录,n个点中与起点奇偶性相同的有num1个,与起点奇偶性不同的有num2个(可用异或实现)。
当num1>=num2时,选先手,每次都选与起点奇偶性不同的点,这样能保证最后剩下的一定是与起点奇偶性相同的点,sum为偶数,先手获胜。
当num1<num2时,选后手,每次选与起点奇偶性相同的点,这样能保证最后剩下的一定是与起点奇偶性不同的点,sum为奇数,后手获胜。
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 100;
bool vis[N];
void solve() {
int n, sx, sy;
cin >> n >> sx >> sy;
vector<int>v[2];
int c0 = 0, c1 = 0;
for (int i = 1; i <= n; ++i) {
vis[i] = 0;
int x, y;
cin >> x >> y;
int t = ((sx^x)+(sy^y)) % 2;//相同则为0,否则为1
v[t].push_back(i);
if (t == 0) c0++;
else c1++;
}
if (c0 >= c1) {
cout << "First\n";
cout.flush();
for (int i = 1; i <= n; ++i) {
if (i % 2 == 0) {
int x;
cin >> x;
vis[x] = 1;
}
else {
//pop掉被用了的点,防止下一步重复选
for (int j = 0; j <= 1; ++j) {
while (v[j].size()) {
int tmp = v[j].size();
if (vis[v[j][tmp - 1]]) v[j].pop_back();
else break;
//两个v数组都去pop直至两个数组的末尾的数都是未访问过的
}
}
if (v[1].size()) {
cout << v[1][v[1].size() - 1] << '\n';
cout.flush();
vis[v[1][v[1].size() - 1]] = 1;
}
else {
cout << v[0][v[0].size() - 1] << '\n';
cout.flush();
vis[v[0][v[0].size() - 1]] = 1;
}
}
}
}
else {
cout << "Second\n";
cout.flush();
for (int i = 1; i <= n; ++i) {
if (i % 2 == 1) {
int x;
cin >> x;
vis[x] = 1;
}
else {
for (int j = 0; j <= 1; ++j) {
while (v[j].size()) {
int tmp = v[j].size();
if (vis[v[j][tmp - 1]]) v[j].pop_back();
else break;
}
}
if (v[0].size()) {
cout << v[0][v[0].size() - 1] << '\n';
cout.flush();
vis[v[0][v[0].size() - 1]] = 1;
}
else {
cout << v[1][v[1].size() - 1] << '\n';
cout.flush();
vis[v[1][v[1].size() - 1]] = 1;
}
}
}
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) solve();
return 0;
}