题意:两个人在Trie树上博弈k局,当前局输的人在下一局中执先手。在一局博弈中,当一个人不能走时,判定另一个人赢。最后一局的结果作为整个游戏的结果。
分析:先手赢的情况为:(1)先手可必胜,也 可败。那么前k-1局败,最后一局胜利即可。
(2)先手只能必胜。 当k为奇数时获胜。
后手赢的情况为:(1)先手必败。
(2)先手只能必胜。 k为偶数。
(本题的状态为取完当前节点的状况)
判定先手是否可必胜:叶子节点为可必胜。如果一个节点的后继存在必胜,那么此节点为必败。如果一个节点的后继全为必败,那么此节点为必胜。
那么判定是否可败也是这样类似:叶子节点为不可败。如果一个节点的后继存在可败,那么此节点为不可败。如果一个节点的后继全为不可败,那么此节点为可败。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 1e5+10;
const int ALP=26;
struct Trie{
int next[maxn][ALP],dp[maxn],dp2[maxn];
int root,p;
int newnode(){
for(int i=0;i<ALP;i++)
next[p][i] = -1;
return p++;
}
void init(){
p = 0;
root = newnode();
}
void insert(char *buf){
int len = strlen(buf);
int now = root;
for(int i=0;i<len;i++){
int c = buf[i]-'a';
if(next[now][c]==-1)
next[now][c] = newnode();
now = next[now][c];
}
}
int dfs(int x){
int co=0 , win = 0;
for(int i=0;i<ALP;i++)if(next[x][i]!=-1){
int u = next[x][i];
win += dfs(u);
co++;
}
if(co==0) return dp[x] = 1;
else if(co>0 && win>0) return dp[x] = 0;
else return dp[x] = 1;
}
int dfs2(int x){
int co=0, fail = 0;
for(int i=0;i<ALP;i++)if(next[x][i]!=-1){
int u = next[x][i];
fail += dfs2(u);
co++;
}
if(co==0) return dp2[x] = 0;
else if(co>0 && fail==0) return dp2[x] = 1;
else return dp2[x] = 0;
}
void solve(int k){
int ok1=0 , ok2=0;
dfs(root);
for(int i=0;i<ALP;i++)if(next[root][i]!=-1){
int u = next[root][i];
if(dp[u]==1) ok1 = 1;
}
dfs2(root);
for(int i=0;i<ALP;i++)if(next[root][i]!=-1){
int u = next[root][i];
if(dp2[u]==1) ok2 = 1;
}
if(ok1==0){
puts("Second");
}else{
if(ok2==0){
if(k&1) puts("First");
else puts("Second");
}else{
puts("First");
}
}
}
}tr;
char s[maxn];
int main(){
int n,k;
tr.init();
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%s",s);
tr.insert(s);
}
tr.solve(k);
return 0;
}