原题大意
给出N个字符串,有2名选手,s一开始是个空串,每回合轮流往里面填字母,使得s为N个字符串其中一个的字串,若不能再往里面填字母则输,输了的下回合先手,问最后一回合谁赢
算法分析
单局游戏可分成如下几种情况:
1.先手必胜(1,0) 2.先手必败(0,1) 3.先手可决定游戏胜败(1,1) 4.游戏胜败由后手决定 (0,0)
属于哪种情况,可种一棵字典树,然后dfs一遍,判断树上每个节点的状态。
情况1:两个玩家轮流胜利,第k局谁是胜者,由k的奇偶性决定。
情况2:很不幸,先手会一直输到底。
情况3:先手可前k-1局都输掉,在第k局击杀对手。
情况4:先手被后手按情况3的思路干掉。
程序代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 1e5+5;
const int SON = 26;
int node_num = 0, n, k;
char s[maxn];
struct Node{
// int cnt;
Node *nxt[SON];
void Init(){
// cnt = 0;
memset(nxt, 0, sizeof(nxt));
}
}node[maxn];
Node * new_node(){
node[node_num].Init();
return &node[node_num++];
}
void Insert(Node * root, char *str){
for(char *p = str; *p; p++)
{
int ch = *p - 'a';
if(root->nxt[ch] == NULL)
root->nxt[ch] = new_node();
root = root->nxt[ch];
// root->cnt++;
}
}
void solve(Node * root, int &x, int &y){
bool fg = true;
x = y = 0;
int u, v;
for(int i = 0; i < SON; i++)
{
if(root->nxt[i])
{
fg = false;
solve(root->nxt[i],u, v);
if(!u) x = 1;
if(!v) y = 1;
}
}
if(fg) x = 0, y = 1;
}
int main(){
scanf("%d%d", &n, &k);
Node * root = new_node();
for(int i = 0; i < n; i++)
{
scanf("%s", s);
Insert(root, s);
}
int x, y;
solve(root, x, y);
if(x && y) puts("First");
else if((k&1) && x) puts("First");
else puts("Second");
return 0;
}