题目大意:
求字符串最小表示。
思路:
本来按照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 }
时间: 2024-12-12 15:03:32