题目链接: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\n", pos1+1); 93 } else { 94 printf("%d 1\n", n-pos2); 95 } 96 } 97 return 0; 98 }
后缀数组:
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\n", pos1+1); 111 } else { 112 printf("%d 1\n", n-pos2); 113 } 114 } 115 return 0; 116 }