[USACO5.5]Hidden Password

题目大意:
  求字符串最小表示。

思路:
  本来按照lbn187的课件,知道SAM可以求字符串最小表示。
  然而他并没有提供例题,就自己找了一道做。
  大体思想就是把字符串复制一遍接在后面,构建SAM,然后每次跑小的转移。
  跑n次以后就跑到了最小表示的末尾,用该状态的len值减去n就是最小表示的起始位置。
  然后交上去就MLE了。
  看了网上的题解发现求最小表示有专门的做法,也是O(n)的,还特别简单,不知道比SAM妙到哪里去了。
  核心思想就是设两个指针i和j,表示目前比较的循环串的开头位置。
  再用k表示目前比较的循环串的长度。
  当目前比较的串字典序一样大时,增加比较的长度。
  当两个不一样大时,大的那个可以直接舍去,将开头位置加上k+1,继续比较。字典序小的不变。
  一直比较到其中一个指针扫完整个字符串,这时小的那个指针就是最小表示的起始位置。

 1 #include<cstdio>
 2 #include<iostream>
 3 int n;
 4 std::string s,t;
 5 int solve() {
 6     int i=0,j=1;
 7     while(i<n&&j<n) {
 8         int k=0;
 9         while(s[(i+k)%n]==s[(j+k)%n]&&k<n) k++;
10         if(k==n) break;
11         (s[(i+k)%n]>s[(j+k)%n]?i:j)+=k+1;
12         if(i==j) i++;
13     }
14     return std::min(i,j);
15 }
16 int main() {
17     std::cin>>n;
18     while(std::cin>>t) {
19         s+=t;
20     }
21     std::cout<<solve()<<std::endl;
22     return 0;
23 }

 

posted @ 2017-09-15 15:36  skylee03  阅读(96)  评论(0编辑  收藏  举报