题目
Andrew, Fedor and Alex are inventive guys. Now they invent the game with strings for two players.
Given a group of n non-empty strings. During the game two players build the word together, initially the word is empty. The players move in turns. On his step player must add a single letter in the end of the word, the resulting word must be prefix of at least one string from the group. A player loses if he cannot move.
Andrew and Alex decided to play this game k times. The player who is the loser of the i-th game makes the first move in the (i + 1)-th game. Guys decided that the winner of all games is the player who wins the last (k-th) game. Andrew and Alex already started the game. Fedor wants to know who wins the game if both players will play optimally. Help him.
中文题目
给定一组n个非空字符串。在游戏中,两个玩家一起构建单词,最初这个词是空的。玩家轮流操作。一个玩家操作时,必须在单词的末尾添加一个字母,结果形成的单词必须是至少一个字符串的前缀。一个玩家如果不能操作就会输掉这一轮。一局共有k轮,第k轮的胜者为最终的胜者。每一轮(非第k轮)的胜者为下一轮的后手。请问第一轮的先手还是后手有必胜策略。
当然,双方都很聪明。
题解
分为两部分
第一部分
是对字符串建trie树,然后如果无路可走则为P状态,如果只能转到N状态为P状态,否则为N状态
这样我们就可以求出每一轮的先手有没有必胜策略
顺便求出每一轮的先手有没有必败策略
(上面那句话是神来之笔???)
第二部分
如果先手既有必胜又有必败策略
他可以前k-1轮一直让自己输,最后一轮胜,最终胜
如果先手只有必胜策略
我们来归纳一下
k=1
显然先手胜
k=2
由于k=1时先手必胜,那么k=2时大家想让自己输,然而先手不存在必输策略,所以后手必胜
k=3
由于k=2时先手必输,那么k=3时大家想让自己赢,由于先手存在必赢策略,所以先手必胜
k=2*a+1
由于k=2*a时先手必输,那么k=2*a+1时大家想让自己赢,由于先手存在必赢策略,所以先手必胜
k=2*a
由于k=2*a-1时先手必胜,那么k=2*a时大家想让自己输,然而先手不存在必输策略,所以后手必胜
如果先手只有必输策略
你是不是认为是只有必赢反过来?
当然
不是啊
由于先手没有必胜策略,后手可以让他一直输,输k轮
所以后手必赢
如果先手都没有
这个就显然是命运都在后手手中
输输输
后手必赢
综上
如果先手既有必胜又有必败策略,必赢
如果先手只有必胜策略,如果k为奇数,先手必赢,反之后手必赢
如果先手没有必胜策略,后手必赢
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int N=100010,M=26,L=100010;
struct node{
int ch[M];
}tree[N];
char s[L];
int len;
int ncnt;
void add_trie(int& rt,int v){
if(!rt){
ncnt++;
rt=ncnt;
}
if(v==len)
return ;
add_trie(tree[rt].ch[s[v]-'a'],v+1);
}
bool is_win(int rt){
for(int i=0;i<26;i++)
if(tree[rt].ch[i])
if(!is_win(tree[rt].ch[i]))
return true;
return false;
}
bool is_lose(int rt){
bool flag=true;
for(int i=0;i<26;i++)
if(tree[rt].ch[i]){
flag=false;
if(!is_lose(tree[rt].ch[i]))
return true;
}
return flag;
}
int main()
{
ncnt=1;
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s);
len=strlen(s);
int rt=1;
add_trie(rt,0);
}
bool win=is_win(1),lose=is_lose(1);
if(win)
if(lose)
printf("First");
else
if(m&1)
printf("First");
else
printf("Second");
else
printf("Second");
}