传送门:【CodeForces】445B A Lot of Games
题目大意:两人一起构造一个串,每人每次向串的末尾放一个字母,必须保证放了这个字母后能够成所给的N个串的前缀,如果某个人不能放时,则另一个人赢。如果谁在第i局输了,那么他就在第i+1局先走。现在问如果要进行K次游戏且以第K次游戏作为最终的结果(第K次游戏赢就是全局赢,输就是全局输),如果两个人足够聪明且都想赢得游戏的胜利,问先手能赢还是后手能赢。
题目分析:首先我们构造一棵字典树,这个很简单,然后重点就是树上的博弈了。
我们需要分析各种胜利的情况:
1.先手必胜且先手可以败,比如aba,abbc就是这种情况,此时只要先手一开始一直输,最后赢即可。
2.先手必败,后手一直赢到结束,所以后手一定赢。
3.先手必胜且先手不能败,一条链就有可能如此,此时k为奇数则先手胜,否则后手胜。
那么怎么判断是否可以先手必胜呢?
假设每个节点表示的是先手取该节点先手是否可以胜,那么很显然边界条件就是叶子节点一定是必胜点,且因为是两个人博弈,所以如果某个节点的后继节点是必胜点,那么对手肯定会走那一个节点,所以该节点一定是必败点,否则该节点就是必胜点。最后,如果根结点是必败点,则说明先手走的第一步一定有一步是必胜点,所以先手必胜,否则先手必败。
既然我们已经知道了先手必胜的条件,那么我们可不可以找到先手可败的条件?
假设每个节点表示的是先手取该节点先手是否可败,那么很明显边界条件就是叶子节点一定是不可败点,且因为是两个人博弈,所以如果某个节点的后继节点是可败点,那么对手一定会选择走可败点,所以该节点是不可败点,否则该节点就是可败点。最后如果根结点是不可败点,则说明先手走的第一步里一定有一步是可败点,所以先手可败,否则先手不可败。
好了,现在我们需要的条件都已经得到了,那么我们就可以愉快的虐题了~
PS:得到这个结论倒是不容易啊。。。真正的AC了以后反而思路越加清晰了。。。一开始能AC真是不可思议啊~
代码如下:
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
#define REP( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define FOR( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REV( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define CLR( a , x ) memset ( a , x , sizeof a )
const int MAXN = 100005 ;
int root , P ;
int next[MAXN][26] ;
char buf[MAXN] ;
int win[MAXN] , lose[MAXN] ;
int n , k ;
void insert ( char buf[] ) {
int now = root ;
for ( int i = 0 ; buf[i] ; ++ i ) {
int x = buf[i] - 'a' ;
if ( !next[now][x] )
next[now][x] = ++ P ;
now = next[now][x] ;
}
}
void dfs ( int u ) {
win[u] = 1 ;
lose[u] = 0 ;
int leaf = 1 ;
REP ( i , 0 , 26 ) {
int v = next[u][i] ;
if ( !v )
continue ;
leaf = 0 ;
dfs ( v ) ;
if ( win[v] )
win[u] = 0 ;
if ( !lose[v] )
lose[u] = 1 ;
}
if ( leaf )
lose[u] = 1 ;
}
void solve () {
P = root = 0 ;
CLR ( next , 0 ) ;
REP ( i , 0 , n ) {
scanf ( "%s" , buf ) ;
insert ( buf ) ;
}
dfs ( root ) ;
int first_can_win = !win[root] ;
int first_can_lose = lose[root] ;
if ( !first_can_win )
printf ( "Second\n" ) ;
else if ( k == 1 || first_can_lose )
printf ( "First\n" ) ;
else
printf ( "%s\n" , k & 1 ? "First" : "Second" ) ;
}
int main () {
while ( ~scanf ( "%d%d" , &n , &k ) )
solve () ;
return 0 ;
}