Hdu 5442 Favorite Donut (2015 ACM/ICPC Asia Regional Changchun Online 最大最小表示法 + KMP)

题目链接:

  Hdu 5442 Favorite Donut

题目描述:

  给出一个文本串,找出顺时针或者逆时针循环旋转后,字典序最大的那个字符串,字典序最大的字符串如果有多个,就输出下标最小的那个,如果顺时针和逆时针的起始下标相同,则输出顺时针。

解题思路:

  看到题目感觉后缀数组可以搞,正准备犯傻被队友拦下了,听队友解释一番,果断锅给队友。赛后试了一下后缀数组果然麻烦的不要不要的(QWQ),还是最大最小表示法 + KMP来的干净利索。

  最大表示法:对于一个长度为len文本串,经过循环旋转得到长度为len的新串,新串是所有循环旋转得到的串中字典序最大的。

  实现方法:对于文本串s,我们可以设定两个指针i, j. 

    刚开始的时候i = 0, j = 1;

    当s[i] == s[j]时, (设定指针k) 从i, j 开始比较,直到s[i+k]!= s[j+k];

    如果s[i+k] < s[j+k], i += k + 1, k = 0;

       因为s[i+k] < s[j+k],证明以i开头的串已经没有意义,以i开头的串一定小于以j开头的串的字典序,所以把指针i移动到(i+k+1)的位置继续和以j开头的串比较;

    依此得,  j += k + 1, k = 0, 当前j 为最大表示串的起始点;

    最后返回min(i, j)即可。(最小表示法把上面的大于改成小于就ok!)

  代码实现:

 1 int Max_Repre (char s[], int n)
 2 {
 3     int i = 0, j = 1, k = 0;
 4     while (i<n && j<n && k<n)
 5     {
 6         int nu = s[(i+k)%n] - s[(j+k)%n];
 7         
 8         if ( !nu )    k++;
 9         else
10         {
11             if (nu < 0)
12                 i += k + 1;
13             else
14                 j += k + 1;
15                 
16             if (i == j)
17                 j ++;
18             k = 0;
19             
20         }
21     }
22     return min (i, j);
23 }

下面是Hdu 5442 代码,还是要比sa好很多的 (惬意!!!!)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 20010;
 8 int Next[maxn];
 9 
10 int Max_Repre (char s[], int n)
11 {
12     int i = 0, j = 1, k = 0;
13     while (i<n && j<n && k<n)
14     {
15         int nu = s[(i+k)%n] - s[(j+k)%n];
16         
17         if ( !nu )    k++;
18         else
19         {
20             if (nu < 0)
21                 i += k + 1;
22             else
23                 j += k + 1;
24                 
25             if (i == j)
26                 j ++;
27             k = 0;
28             
29         }
30     }
31     return min (i, j);
32 }
33 
34 int Get_Next (char s[], int n)
35 {
36     int k = -1, i = 0;
37     Next[0] = -1;
38     
39     while (i < n)
40     {
41         if (k == -1 || s[k]==s[i])
42             Next[++i] = ++k;
43 
44         else
45             k = Next[k];
46     }
47     
48     if (n % (n - Next[n]))
49         return n;
50     return n - Next[n];
51 }
52 
53 void display (char a[], char s[], int x, int n)
54 {
55     for (int i=0; i<n; i++)
56         a[i] = s[(x+i)%n];
57         
58     a[n] = 0;
59 }
60 
61 //a大,return true,b大 return false
62 bool Judge (int a, int b, char A[], char B[])
63 {
64     int k = strcmp (A, B);
65     
66     if (k == 0)
67         return a<=b ? true:false;
68     return k>0?true:false;
69 }
70 
71 int main ()
72 {
73     int t, n, k, a, b;
74     char S[maxn], A[maxn], B[maxn];
75     scanf ("%d", &t);
76     
77     while (t --)
78     {
79         scanf ("%d %s", &n, S);
80         
81         k = Get_Next (S, n);
82         a = Max_Repre (S, n);
83         display (A, S, a, n);
84         
85         strrev (S);
86         b = Max_Repre (S, n);
87         display (B, S, b, n);
88         b = (n - b - 1) % k;
89         
90         if (Judge (a, b, A, B))
91             printf ("%d 0\n", a + 1);
92         else
93             printf ("%d 1\n", b + 1);
94     }
95     return 0;
96 }

 

posted @ 2015-09-18 20:26  罗茜  阅读(239)  评论(0编辑  收藏  举报