題目連結:http://codeforces.com/problemset/problem/455/B
題意:
給你n個字串,然後進行k局遊戲。
每局遊戲開始有一個空串,然後雙方輪流給這個串的末尾新增字元,並保證新字串是n個字串中至少一個串的字首。
當一方不能新增字元時,這一方輸,遊戲結束。
每場遊戲結束後,這場遊戲輸的人會成為下一句遊戲的先手。
誰贏得了最後一場比賽,誰才會真正贏得比賽。
問你最終真正贏得比賽的人,是第一局遊戲的先手還是後手(分別稱為First和Second)。
題解:
先考慮單局遊戲。
先對原來的n個串,建立一棵trie樹。
那麼原遊戲就變成了:
最初有一個棋子在根節點,雙方輪流將棋子向下移一格,不能移動的一方輸。
因為每場遊戲都是一模一樣的,所以每場遊戲先手必勝還是必敗也是確定的。
所以遊戲的最終贏家取決於,誰能夠拿到最後一場遊戲的必勝方。
所以要求的也就不單單是先手是必勝還是必敗了。
而是要分別求:先手能否必勝,和先手能否必敗。
一遍dfs就能解決。
然後分情況討論:
(1)先手只能必勝,不能必敗:
則奇數局的先手是First,First必勝。
偶數局的先手是Second,Second必勝。
(2)先手可以必勝,也可以必敗:
那麼First會一直讓自己輸,一直讓自己是先手,直到最後一局再贏。
所以此時First必勝。
(3)先手不能必勝,只能必敗:
也就是無論怎樣操作,First一直都是先手,所以Second必勝。
(4)先手不能必勝,也不能必敗:
也就是後手既可以必勝,也可以必敗。
所以後手會一直讓自己贏,一直讓自己是後手,所以Second必勝。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 100005 5 #define MAX_L 100005 6 #define MAX_A 30 7 8 using namespace std; 9 10 struct Node 11 { 12 int nex[MAX_A]; 13 Node() 14 { 15 memset(nex,0,sizeof(nex)); 16 } 17 }; 18 19 int n,k; 20 int cnt=1; 21 bool win[MAX_L]; 22 bool lose[MAX_L]; 23 string s[MAX_N]; 24 Node node[MAX_L]; 25 26 void read() 27 { 28 cin>>n>>k; 29 for(int i=1;i<=n;i++) 30 { 31 cin>>s[i]; 32 } 33 } 34 35 void init_trie() 36 { 37 for(int i=1;i<=n;i++) 38 { 39 int now=1; 40 for(int j=0;j<s[i].size();j++) 41 { 42 if(!node[now].nex[s[i][j]-'a']) 43 { 44 node[now].nex[s[i][j]-'a']=++cnt; 45 } 46 now=node[now].nex[s[i][j]-'a']; 47 } 48 } 49 } 50 51 void dfs(int now) 52 { 53 win[now]=lose[now]=false; 54 bool flag=true; 55 for(int i=0;i<26;i++) 56 { 57 if(node[now].nex[i]) 58 { 59 dfs(node[now].nex[i]); 60 win[now]|=(!win[node[now].nex[i]]); 61 lose[now]|=(!lose[node[now].nex[i]]); 62 flag=false; 63 } 64 } 65 if(flag) lose[now]=true; 66 } 67 68 void work() 69 { 70 init_trie(); 71 dfs(1); 72 if(win[1] && !lose[1]) cout<<((k&1)?"First":"Second")<<endl; 73 else if(win[1] && lose[1]) cout<<"First"<<endl; 74 else cout<<"Second"<<endl; 75 } 76 77 int main() 78 { 79 read(); 80 work(); 81 }