问题 F: Removing Coins
时间限制: 1 Sec 内存限制: 128 MB
提交: 35 解决: 15
[提交] [状态] [命题人:admin]
题目描述
Takahashi and Aoki will play a game on a tree. The tree has N vertices numbered 1 to N, and the i-th of the N−1 edges connects Vertex ai and Vertex bi.
At the beginning of the game, each vertex contains a coin. Starting from Takahashi, he and Aoki will alternately perform the following operation:
Choose a vertex v that contains one or more coins, and remove all the coins from v.
Then, move each coin remaining on the tree to the vertex that is nearest to v among the adjacent vertices of the coin's current vertex.
The player who becomes unable to play, loses the game. That is, the player who takes his turn when there is no coin remaining on the tree, loses the game. Determine the winner of the game when both players play optimally.
Constraints
·1≤N≤2×105
·1≤ai,bi≤N
·ai≠bi
·The graph given as input is a tree.
输入
Input is given from Standard Input in the following format:
N
a1 b1
a2 b2
:
aN−1 bN−1
输出
Print First if Takahashi will win, and print Second if Aoki will win.
样例输入
复制样例数据
3
1 2
2 3
样例输出
First
提示
Here is one possible progress of the game:
·Takahashi removes the coin from Vertex 1. Now, Vertex 1 and Vertex 2 contain one coin each.
·Aoki removes the coin from Vertex 2. Now, Vertex 2 contains one coin.
·Takahashi removes the coin from Vertex 2. Now, there is no coin remaining on the tree.
·Aoki takes his turn when there is no coin on the tree and loses.
题意:
给定一棵树,树上每个节点初始时有一个硬币。每次操作可以选择一个硬币数大于0的节点u,拿走u上的所有硬币,然后其它所有节点上的硬币向u的方向移动一条边的距离。两个人轮流操作,不能移动的人输。
思路:
可以发现,我们只需关心节点上是否有硬币,不需要关系硬币的数量。
删掉的点有两种情况
1. 不是叶子节点,这可以看做把树的所有叶子节点都删掉,树的直径长度减2。
2. 是叶子节点,如果是直径的端点,则直径长度减1,如果不是直径的端点,则直径长度减2。
至于为什么和直径有关系,因为每次相当于删掉一层叶子,那你删删删,最后肯定会在直径上剩下点的,因为它最长嘛
可以发现直径只能减小1或2,那么(可以找规律,也可以sg打表,总之,这部分就是一个基础的nim博弈咯)
得到的结果是如果树的直径%3==2那么second,否则first
得到了个两次bfs得直径的代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+7;
int head[maxn],tot = 1;
int Next[maxn<<1],to[maxn<<1];
void add(int u,int v){
to[tot] = v,Next[tot] = head[u];
head[u] = tot++;
}
int n;
int deep[maxn];
int bfs(int s){
queue<int> Q;
memset(deep,0,sizeof deep);
deep[s] = 1;
Q.push(s);
int ans = s;
while(!Q.empty()){
int u = ans = Q.front();
Q.pop();
for(int i=head[u];i;i=Next[i])if(!deep[to[i]]){
deep[to[i]] = deep[u]+1;
Q.push(to[i]);
}
}
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
int cnt = deep[bfs(bfs(1))];
printf("%s\n",cnt%3==2?"Second":"First");
return 0;
}