本文将用三个算法来解决此题
提示: ( 如果你是顺着INTERMEDIATE往下做的这个题有一个明显的思路)
1. 想办法使用后缀数组 , 因为题目要求的是一种字符串的循环表示形式(AKA 字符串表示法) , 那么可以把字符串写两遍然后跑一跑后缀数组啊
2. 跑出来后SA[1]不一定是答案 , 因为还有可能是后面那个加上字符串的某个后缀 , 所以要找第一个SA小于原来字符串长度的后缀.......
3. 还没完 , 找到后还需要往后一直找 , 找到一个SA最小并且中途的HEIGHT不小于字符串长度的下标....(有点废话是吧)
实现后的代码如下(等会贴出来)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <vector> #include <deque> #include <stack> #include <algorithm> using namespace std; const int maxn = 2e4+1e2; int s[maxn] , n; int t1[maxn] , t2[maxn] , c[maxn] , sa[maxn] , height[maxn] , Rank[maxn]; void SA(int m) { int *x = t1 , *y = t2; for(int i=0;i<m;i++) c[i] = 0; for(int i=0;i<n;i++) c[x[i] = s[i]] ++; for(int i=1;i<m;i++) c[i] += c[i-1]; for(int i=0;i<n;i++) sa[--c[x[i]]] = i; for(int k=1;k<=n;k*=2) { int p = 0; for(int i=n-k;i<n;i++) y[p++] = i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++] = sa[i]-k; for(int i=0;i<m;i++) c[i] = 0; for(int i=0;i<n;i++) c[x[i]] ++; for(int i=1;i<m;i++) c[i] += c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]] = y[i]; swap(x , y); p=1; x[sa[0]] = 0; for(int i=1;i<n;i++) x[sa[i]] = y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k] ? p-1 : p++; if(p>=n) break; m = p; } } void getHeight() { for(int i=0;i<n;i++) Rank[sa[i]] = i; int k = 0 , j; for(int i=0;i<n-1;i++) { if(k) k--; j = sa[Rank[i]-1]; while(s[i+k] == s[j+k]) k++; height[Rank[i]] = k; } } int id(char c) { return c-'a'+1; } char ss[maxn]; int main(int argc, char *argv[]) { int t; scanf("%d",&t); while(t--) { scanf("%s",ss); int len = strlen(ss); n = 0; for(int i=0;i<len;i++) s[n++] = id(ss[i]); for(int i=0;i<len;i++) s[n++] = id(ss[i]); s[n++] = 0; SA(28); getHeight(); for(int i=0;i<n;i++) if(sa[i]<len) { int res = sa[i]; while(height[i+1]>=len && i+1<n) { i++; if(sa[i]<len) res = min(res , sa[i]); } cout<<res+1<<endl; break; } } return 0; }
第二个思路 , 后缀自动机...........如果不看不慌不忙的博客我也不知道这个数据结构 , 研究了陈姐姐(CLJ)的论文(自行百度)。 然后顺着自动机找一条最小路径就OK了
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <vector> #include <deque> #include <algorithm> #include <stack> #include <string> #include <map> #include <set> using namespace std; const int sigmaSize = 26; const int maxn = 1e4+1e2; struct state { state* go[sigmaSize] , *pre; int Max; state(int _Max = 0): pre(0), Max(_Max) { memset(go , 0 , sizeof(go)); } }; int sz; state pool[maxn*3]; inline state* newnode(int _Max = 0) { memset(pool[sz].go , 0 , sizeof(pool[sz].go)); pool[sz].pre = 0; pool[sz].Max = _Max; return &pool[sz++]; } state *root , *last; void extend(int w) { state* p = last; state* np = newnode(p->Max+1); while(p && p->go[w] ==0) p->go[w] = np , p = p->pre; if(p) { state* q = p->go[w]; if(p->Max+1 == q->Max) np->pre = q; else { state* nq = newnode(p->Max+1); memcpy(nq->go , q->go , sizeof q->go ); nq->pre = q->pre; q->pre = nq; np->pre = nq; while(p && p->go[w] == q) p->go[w] = nq , p = p->pre; } } else np->pre = root; last = np; } int query(int n) { state* now = root; while(n--) for(int i=0;i<sigmaSize;i++) if(now->go[i]) { now = now->go[i]; break; } return now->Max; } inline int id(char c) { return c-'a'; } char s[maxn]; int main() { freopen("in","r",stdin); int t , n; scanf("%d" , &t); while(t-- && scanf("%s",s)) { sz = 0; root = newnode(); last = root; n = strlen(s); for(int k=0;k<2;k++) for(int i=0;i<n;i++) extend(id(s[i])); printf("%d\n",query(n)-n+1); } return 0; }
代码如下:(等会贴出)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <string> #include <vector> #include <deque> #include <stack> #include <algorithm> using namespace std; const int maxn = 1e4+1e2; char s[maxn]; int main(int argc, char *argv[]) { int t; scanf("%d",&t); while(t--) { scanf("%s",s); int i =0 , j = 0 , n = (int)strlen(s) , k; while(i<n && j<n) { if(i==j) j++; k = 0; while(k<=n && s[(i+k)%n]==s[(j+k)%n]) k++; if(s[(i+k)%n]>s[(j+k)%n]) i+=k+1; else j+=k+1; } printf("%d\n",i+1); } return 0; }
时间从上到下依次变快 , 可以自行比较