hdu5442 Favorite Donut

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5442

题目大意:给你一个长度为n的字符串,将它首尾相连成环。问你这个环上找一个长度为n的字典序最大的串(你可以沿顺时针或逆时针找),如果有多个这样的串,输出首字母标号最小的,如果还有多个,输出顺时针的

解:

1、最小表示法解(时间复杂度:O(n))

最小表示法~

2、后缀数组(时间复杂度:O(logn))

比赛的时候想到的方法,然而并没有写出来,不好写+高时间复杂度=不推荐

最小表示法:

 1 /*
 2  * Problem:  
 3  * Author:  SHJWUDP
 4  * Created Time:  2015/9/16 星期三 16:18:36
 5  * File Name: 1001.cpp
 6  * State: 
 7  * Memo: 
 8  */
 9 #include <iostream>
10 #include <cstdio>
11 #include <vector>
12 #include <cstring>
13 #include <algorithm>
14 
15 using namespace std;
16 
17 struct KMP {
18     int n;
19     string T;    //target string
20     vector<int> nt;
21     KMP(const char * _str) {
22         n=strlen(_str);
23         T.assign(_str, _str+n);
24         getFail();
25     }
26     void getFail() {
27         nt.resize(n+1);
28         nt[0]=-1;
29         for(int i=0, j=-1; i<n; ) {
30             if(j==-1 || T[i]==T[j]) {
31                 nt[++i]=++j;
32             } else j=nt[j];
33         }
34     }
35     int match(const char * P) {//pattern string
36         //在P中找T
37         int ret=-1;
38         for(int i=0, j=0; P[i]; ) {
39             if(j==-1 || P[i]==T[j]) {
40                 ++i;
41                 if(++j==n) {
42                     if(P[i]) ret=i-n;
43                 }
44             } else j=nt[j];
45         }
46         return ret;
47     }
48 };
49 
50 int maximum_representation(const char * s) {
51     int i, j, k, len=strlen(s);
52     for(i=0, j=1, k=0; i<len && j<len && k<len; ) {
53         int tmp=s[(i+k)%len]-s[(j+k)%len];
54         if(tmp==0) ++k;
55         else {
56             if(tmp>0) j+=k+1;//改成小于号是最小表示法
57             else i+=k+1;
58             if(i==j) ++j;
59             k=0;
60         }
61     }
62     return min(i, j);
63 }
64 
65 int n;
66 int main() {
67 #ifndef ONLINE_JUDGE
68     freopen("in", "r", stdin);
69     //freopen("out", "w", stdout);
70 #endif
71     int T;
72     scanf("%d", &T);
73     while(T--) {
74         scanf("%d", &n);
75         string str1;
76         cin>>str1;
77         int pos1=maximum_representation(str1.c_str());
78         string str2(str1.rbegin(), str1.rend());
79         int pos2=maximum_representation(str2.c_str());
80         str1+=str1;
81         str2+=str2;
82         KMP kmp(str2.substr(pos2, n).c_str());
83         pos2=kmp.match(str2.c_str());
84         auto cmp=[&]()->bool {
85             for(int i=0; i<n; ++i) {
86                 if(str1[pos1+i]!=str2[pos2+i])
87                     return str1[pos1+i]>str2[pos2+i];
88             }
89             return pos1<=n-pos2-1;
90         };
91         if(cmp()) {
92             printf("%d 0
", pos1+1);
93         } else {
94             printf("%d 1
", n-pos2);
95         }
96     }
97     return 0;
98 }
View Code

后缀数组:

  1 /*
  2  * Problem:  
  3  * Author:  SHJWUDP
  4  * Created Time:  2015/9/14 星期一 16:06:34
  5  * File Name: 1001.cpp
  6  * State: 
  7  * Memo: 
  8  */
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <vector>
 12 #include <cstring>
 13 #include <algorithm>
 14 
 15 using namespace std;
 16 
 17 struct SuffixArray {
 18     static const int SIGMA_SIZE=256;
 19     int n;//串长+1
 20     vector<int> str;//str中最后一个元素为0
 21     vector<int> sa;//第i大后缀为str[sa[i]:]
 22     vector<int> rank;//str坐标为i的后缀的字典序排名
 23     vector<int> height;//sa[i-1]和sa[i]的最长公共前缀(LCP)
 24     SuffixArray(const char * _str) {
 25         n=strlen(_str)+1;
 26         str.resize(n);
 27         for(int i=0; i<n; ++i) str[i]=_str[i];
 28         build_sa();
 29     }
 30     void build_sa(int m=SIGMA_SIZE) {
 31         sa.assign(n, 0);
 32         vector<int> x(n, 0), y(n, 0), c(m, 0);//c(字符计数)
 33         //x[i]:str坐标为i的x值rank
 34         //y[i]:y值第i大的str坐标
 35         //*y数组中前k个为y段串不足k长度的串对应str坐标
 36         for(int i=0; i<n; ++i) ++c[x[i]=str[i]];
 37         for(int i=1; i<m; ++i) c[i]+=c[i-1];
 38         for(int i=n-1; i>=0; --i) sa[--c[x[i]]]=i;
 39         for(int k=1; k<=n; k<<=1) {
 40             int p=0;
 41             //直接利用sa数组排序第二关键字
 42             for(int i=n-k; i<n; ++i) y[p++]=i;
 43             for(int i=0; i<n; ++i) if(sa[i]>=k) y[p++]=sa[i]-k;
 44             //基数排序第一关键字
 45             c.assign(m, 0);
 46             for(int i=0; i<n; ++i) ++c[x[y[i]]];
 47             for(int i=1; i<m; ++i) c[i]+=c[i-1];
 48             for(int i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i];
 49             //根据sa和y数组计算新的x数组
 50             swap(x, y);
 51             p=1; x[sa[0]]=0;
 52             for(int i=1; i<n; ++i) {
 53                 x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
 54             }
 55             if(p >= n)break;
 56             m = p;//下次基数排序的最大值
 57         }
 58         getHeight();
 59     }
 60     void getHeight() {
 61         rank.resize(n);
 62         height.resize(n);
 63         for(int i=1; i<n; ++i) rank[sa[i]]=i;
 64         for(int i=0, k=0; i<n-1; ++i) {
 65             //h[i]=height[rank[i]]
 66             if(k) --k;    //h[i]>=h[i-1]-1
 67             int j=sa[rank[i]-1];
 68             while(str[i+k]==str[j+k]) ++k;
 69             height[rank[i]]=k;
 70         }
 71     }
 72 };
 73 
 74 int n;
 75 bool cmp(string a, string b, int x, int y) {
 76     for(int i=0; i<n; ++i) {
 77         if(a[x+i]!=b[y+i]) return a[x+i]>b[y+i];
 78     }
 79     return x<=n-y-1;
 80 }
 81 int main() {
 82 #ifndef ONLINE_JUDGE
 83     freopen("in", "r", stdin);
 84     //freopen("out", "w", stdout);
 85 #endif
 86     int T;
 87     scanf("%d", &T);
 88     while(T--) {
 89         scanf("%d", &n);
 90         string str1;
 91         cin>>str1;
 92         string str2(str1.rbegin(), str1.rend());
 93         str1+=str1;
 94         str2+=str2;
 95         SuffixArray sa1(str1.c_str());
 96         int pos1;
 97         for(int i=sa1.n-1; i>=1; --i) {
 98             if(sa1.sa[i]<n) {
 99                 pos1=sa1.sa[i]; break;
100             }
101         }
102         SuffixArray sa2(str2.c_str());
103         int pos2=-1, mi=n;
104         for(int i=sa2.n-1; i>=1; --i) {
105             if(pos2!=-1) mi=min(mi, sa2.height[i+1]);
106             if(mi<n) break;
107             if(sa2.sa[i]<n) pos2=sa2.sa[i];
108         }
109         if(cmp(str1, str2, pos1, pos2)) {
110             printf("%d 0
", pos1+1);    
111         } else {
112             printf("%d 1
", n-pos2);
113         }
114     }
115     return 0;
116 }
View Code
原文地址:https://www.cnblogs.com/shjwudp/p/4814172.html