兩我的輪流在一個字符串上刪掉一個字符,沒有字符可刪的人輸掉遊戲ios
刪字符的規則以下:ide
1. 每次從一個字符串中選取一個字符,它是一個長度至少爲 3 的奇迴文串的中心函數
2. 刪掉該字符,同時,他選擇的那個字符串分紅了兩個獨立的字符串spa
如今問,先手是否必勝,若是先手必勝,輸出第一步應該刪掉第幾個字符,有多解的話,輸出序號最小的那個code
字符串的長度不超過5000,只包含小寫英文字母blog
能夠這樣考慮:將全部的長度大於等於 3(其實只須要找長度爲 3 的就行)的奇迴文串的中心標記出來遊戲
咱們將連續的中心視爲一個片斷,那麼,顯然,遊戲是進行在片斷上面的,因此,遊戲被分解成了多個子遊戲的和字符串
對於每個片斷(子游戲),咱們考慮它的 sg 函數,顯然,sg 函數只和這個片斷的長度有關,因而定義狀態 sg[len] 表示長度爲 len 的片斷的 sg 值。怎麼獲得當前狀態的下一子狀態呢?get
若是刪掉的是片斷的兩端,子狀態分紅了一個長度爲 0 和長度爲 len-2 的子片斷string
若是刪掉的是片斷的中間,子狀態分紅了一個長度爲 i 和長度爲 len-3-i 的子片斷
這樣,暴力出 sg 值,再依次的枚舉第一次刪掉的字符就能夠解決這題了
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 5 using namespace std; 6 7 const int N=5006; 8 9 char buff[N]; 10 int sg[N]; 11 12 int GET_SG(int len) { 13 if(sg[len]!=-1) return sg[len]; 14 bool vs[N]; 15 memset(vs, 0, sizeof vs); 16 vs[GET_SG(len-2)]=1; 17 for(int i=1; i+i<len; i++) vs[GET_SG(i-1)^(GET_SG(len-2-i))]=1; 18 for(int i=0; i<N; i++) if(!vs[i]) return sg[len]=i; 19 } 20 21 int hehe(int L, int R) { 22 int sum=0; 23 for(int i=L+1; i<R; i++) if(buff[i-1]==buff[i+1]) { 24 int id=i; 25 while(i<R && buff[i+1]==buff[i-1]) i++; 26 sum^=sg[i-id]; 27 } 28 return sum; 29 } 30 31 int main() { 32 memset(sg, -1, sizeof sg); 33 sg[0]=0, sg[1]=1; 34 for(int i=2; i<N; i++) if(sg[i]==-1) GET_SG(i); 35 while(scanf("%s", buff)!=EOF) { 36 bool flag=1; 37 for(int i=1, len=(int)strlen(buff); i<len-1; i++) { 38 if(buff[i-1]!=buff[i+1]) continue; 39 if(hehe(0, i-1)^hehe(i+1, len-1)) continue; 40 printf("First\n%d\n", i+1); 41 flag=0; 42 break; 43 } 44 if(flag) printf("Second\n"); 45 } 46 return 0; 47 }