题意:
给定n个字符串,一开始有一个空串。
两个人轮流操作,每次操作将一个字符加到空串后面,要求加入新字符之后串必须是某个串的前缀。
最后不能进行操作的人输。
总共进行k次比赛,第k次比赛输的人才是真的输。
第x次比赛输的人在第x+1次比赛作为先手。
问最后谁赢。
数据范围:n<=1e5,k<=1e9
解法:
每个前缀对自己的下一个前缀建有向边,那么这个博弈就是DAG上博弈
但是暴力建边会出现重复边,因为是前缀所以想到字典树,那么问题就变成字典树上的DAG博弈了。
因为:
总共进行k次比赛,第k次比赛输的人才是真的输。
第x次比赛输的人在第x+1次比赛作为先手。
所以对于每个节点,需要定义 必胜,必败,胜负可控,胜负被控 4种状态。
然后在字典树上dfs自底向上计算出先手的状态。
如果第一次比赛先手是可控,那么最后一定赢。
如果第一次比赛先手是被控或者必败(这时候先手一定输,会演变成k次都是先手在比且都输),最后一定输。
否则就是轮流先手,根据k的奇偶性判断胜负即可。
code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=1e5+5;
struct Trie{
int a[maxm][26],tot;//数组大小为(总长度*字符集大小)
int d[maxm];
void add(char *s){
int len=strlen(s+1);
int node=0;
for(int i=1;i<=len;i++){
int v=s[i]-'a';
if(!a[node][v])a[node][v]=++tot;
node=a[node][v];
}
}
void dfs(int x){//0必败,1必胜,2可控,3被控
int num=0;
int cnt[4]={0};
for(int i=0;i<26;i++){
if(a[x][i]){
int v=a[x][i];
dfs(v);
cnt[d[v]]++;
num++;
}
}
if(!num){//没路走了,必败
d[x]=0;return ;
}
if(cnt[0]&&cnt[1]){//可控
d[x]=2;return ;
}
if(cnt[3]){//令对方被控,可控
d[x]=2;return ;
}
//!cnt[3]
if(cnt[0]){
d[x]=1;return ;
}
if(cnt[1]){
d[x]=0;return ;
}
if(cnt[2]){//对方可控,被控
d[x]=3;return ;
}
}
}T;
char s[maxm];
int n,k;
signed main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
T.add(s);
}
T.dfs(0);
if(T.d[0]==2){//可控
puts("First");
}else if(T.d[0]==3||T.d[0]==0){//被控/输
puts("Second");
}else{
if(k&1){
puts("First");
}else{
puts("Second");
}
}
return 0;
}