Codeforces Round #184 (Div. 2) E. Playing with String(博弈)

 

題目大意

 

兩我的輪流在一個字符串上刪掉一個字符,沒有字符可刪的人輸掉遊戲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 }
E. Playing with String

 

題目連接 & AC 通道

 

Codeforces Round #184 (Div. 2) E. Playing with String

相關文章
相關標籤/搜索