题目
最小表示法模板
求把一个字符串首尾相连,从任意位置断开后形成的字符串中字典序最小的一个
思路
将长度为n的字符串s复制并接在末尾,记为ss
设B[i]
表示以i开头的循环同构字符串,则有B[i] = ss[i ~ i+n-1]
考虑对于任意i,j, B[i] 和 B[j] 的比较过程
设 B[i] B[j] 前 k 位相等,即ss[i ~ i+k] = ss[j ~ j+k]
若ss[i+k] > ss[j+k]
, 可知 B[i] 不是最小表示,因为 B[j] 更小
同理 B[i+1], B[i+2], ... , B[i+k]
都不是最小表示(有B[j+1], B[j+2], ... , B[j+k]
)
因此可以跳过这一段,直接令i = i + k + 1
若ss[i+k] < ss[j+k]
,同理对 j 操作
代码
#include <iostream>
#include <cstdio>
int min(int a, int b)
{
return a < b ? a : b;
}
int main(){
std::string s;
int t;
std::cin >> t;
while(t--)
{
std::cin >> s;
int n = s.length();
s += s;
int i = 1, j = 2, k;
while(i <= n && j <= n)
{
for(k = 0; k <n && s[i+k-1] == s[j+k-1]; k++);
if(k == n) break;
if(s[i+k-1] > s[j+k-1])
{
i = i + k + 1;
if(i == j) i++;
}
else
{
j = j + k + 1;
if(i == j) j++;
}
}
//i j 之一大于 n
printf("%d\n", min(i, j));
}
return 0;
}