關於如何求一個(不完整)字符串的最小循環節:ide
n - nex[n - 1]便可。spa
若n % 循環節長度 == 0則表示這個字符串可由若干個循環節構成。code
不然最後一個循環節有殘缺。blog
回到本題:字符串
首先行列分開。get
一個直觀的想法是求出最小循環節的lcm,可是諸君請看:io
2 8event
abDQRVabclass
aaaabaaacli
而後怎麼作呢?
有一種作法是枚舉行的長度,而後列用KMP
而後,略加思索,咱們行也能夠用KMP啊......
而後雙KMP搞定。
調了很久是由於把while寫成了if......
1 #include <cstdio> 2 3 const int N = 10010, M = 100; 4 5 char s[N][M]; 6 int nex[N], m, n; 7 8 inline bool equala(int a, int b) { 9 for(int i = 0; i < m; i++) { 10 if(s[a][i] != s[b][i]) { 11 return 0; 12 } 13 } 14 return 1; 15 } 16 17 inline bool equalb(int a, int b) { 18 for(int i = 0; i < n; i++) { 19 if(s[i][a] != s[i][b]) { 20 return 0; 21 } 22 } 23 return 1; 24 } 25 26 inline int geta() { 27 nex[0] = 0; 28 for(int i = 1, j = 0; i < n; i++) { 29 while(j && !equala(i, j)) { 30 j = nex[j - 1]; 31 } 32 if(equala(i, j)) { 33 j++; 34 } 35 nex[i] = j; 36 } 37 return n - nex[n - 1]; 38 } 39 40 inline int getb() { 41 nex[0] = 0; 42 for(int i = 1, j = 0; i < m; i++) { 43 while(j && !equalb(i, j)) { 44 j = nex[j - 1]; 45 } 46 if(equalb(i, j)) { 47 j++; 48 } 49 nex[i] = j; 50 } 51 return m - nex[m - 1]; 52 } 53 54 int main() { 55 while(scanf("%d%d", &n, &m) != EOF) { 56 for(int i = 0; i < n; i++) { 57 scanf("%s", s[i]); 58 } 59 60 int c = geta(); 61 int d = getb(); 62 printf("%d\n", c * d); 63 } 64 return 0; 65 }