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 }
AC代码

 

posted @ 2018-08-13 22:44  garage  阅读(86)  评论(0编辑  收藏  举报