题目链接:http://codeforces.com/problemset/problem/455/B
题意:两个人玩游戏,给n个字符串,两个人轮流选一个字母加到字符串后面,一开始字符串是空的,而且加完后当前字符串必须是字符串集合中一个字符串的前缀,谁无法再添加字符串谁就输了,他们玩k局这个游戏,上一局输的人下一局先手,问第一局的先手必胜还是后手必胜。
思路:首先建一个trie树去保存这些字符串,剩下的就是一个博弈问题了。如果先手可以控制输赢,那么他可以前面几局一直输下去,最后一局再赢;先手怎么走都赢,那么下一局就是对手先手,下一局再回到自己先手...就可以通过判断奇偶来得到解决;先手必输,那么下一局还是自己先手,一直输下去,永无翻身之地....;先手不管怎么走,后手都可以控制输赢,更赢不了。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <sstream>
#include <queue>
#include <utility>
using namespace std;
#define rep(i,j,k) for (int i=j;i<=k;i++)
#define Rrep(i,j,k) for (int i=j;i>=k;i--)
#define Clean(x,y) memset(x,y,sizeof(x))
#define LL long long
#define ULL unsigned long long
#define inf 0x7fffffff
#define mod 100000007
const int maxn = 100009;
const int maxnode = 100009;
const int sz = 26;
LL n,k;
struct trie
{
int next[maxnode][sz];
int size; // 当前大小
trie()
{
size = 0;
memset(next,0,sizeof(next));
}
void insert(char s[]) //插入一个字符串
{
int len = strlen(s);
int now = 0;
for( int i = 0; i < len; i++ )
{
int index = s[i] - 'a'; //当前字符对应的下一个节点的下标
if ( !next[now][index] )
{
next[now][index] = ++size; //新开一个节点
}
now = next[now][index];
}
}
}T;
char temp[maxn];
int can( int now , int len ) // 0 1 2 3 -> 2表示必胜 1 必输 3可以控制输赢 0被控制输赢
{
int temp;
bool f1,f2,f0;
f1 = f2 = f0 = false;
rep(i,0,25)
if ( T.next[now][i] )
{
temp = can( T.next[now][i] , len+1 );
if ( temp == 0 ) return 3; //对手被控制输赢
else if ( temp == 1 ) f2 = true;//对手必输
else if ( temp == 2 ) f1 = true;
else if ( temp == 3 ) f0 = true;
}
if ( f1 && f2 ) return 3; //又可以赢又可以输
if ( f1 ) return 1;
if ( f2 ) return 2;
if ( f0 ) return 0; //只能被控制输赢
return 1; //剩下的情况就只有必输了
}
int main()
{
cin>>n>>k;
getchar();
rep(i,1,n)
{
gets(temp);
T.insert(temp);
}
int ans = can( 0 , 1 ); // 2 win 1 lose
if ( ans == 3 || ( ans == 2 && ( k & 1 ) ) )
puts("First");
else puts("Second");
return 0;
}