poj2185 Milking Grid
关于如何求一个(不完整)字符串的最小循环节:
n - nex[n - 1]即可。
若n % 循环节长度 == 0则表示这个字符串可由若干个循环节构成。
否则最后一个循环节有残缺。
回到本题:
首先行列分开。
一个直观的想法是求出最小循环节的lcm,但是诸君请看:
2 8
abDQRVab
aaaabaaa
然后怎么做呢?
有一种做法是枚举行的长度,然后列用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 }