最小(大)表示法
一个字符串扩增到两倍的时候,在0~n-1的范围中都可以通过循环找到与原字符串同构的字符串,但是其中有两个特殊的字符串,字典序最大和字典序最小(数字也可以当做字典序来处理),直接暴力找到最小或者最大的算法复杂度是O(n^2) ,有一种最小(大)表示法可以解决此问题。
百度论文:https://wenku.baidu.com/view/c6c5e7335a8102d276a22fa6.html
博客解析:http://blog.youkuaiyun.com/zy691357966/article/details/39854359
我的理解是:扩增之后的字符串,初始指针位置不同,但是通过有条件的移动(最大或者最小)都可以找到最优的位置。
- 需要注意的点是:有可能出现多个相同的点使得最大(最小)有多个位置,但是其找到的第一个便是最优的字典序。
HDU5442
题意:
给定一个字符构成的环,在这个环中选定一个起点,顺时针或逆时针使得以选定点为起点的字符串字典序最大。如果有多个答案,优先选择使起点位置在原字符串中编号较小的,如果还有多个答案,优先选择顺时针。
思路:
对于正序,直接用最大表示法来记录答案,对于逆序先逆序存储,然后找到位置最大的最优字典序(也就是对应初始位置最小)。然后比较输出。
- 这里有一个疑惑点,对于逆序找位置最大的时候需要一直找,但是第一个找到的就能直接输出最终的位置,这是让我不理解的地方。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <math.h>
#include <stdlib.h>
using namespace std;
const int maxn = 2e4+10;
char s[maxn*2];
char s1[maxn*2];
char ans1[maxn];
char ans2[maxn];
int n;
int getMaxStringPos(char *x,int l)
{
int i,j,k;
i = 0,j = 1,k = 0;
while(i < l && j < l) {
k = 0;
while(x[i+k] == x[j+k] && k < l) k++;
if(k == l) return min(i,j);
if(x[i+k] > x[j+k])
if(j+k+1 > i) j += k+1;
else j = i+1;
else
if(i+k+1 > j) i += k+1;
else i = j+1;
}
return min(i,j);
}
int getMaxnixuPos(char *x,int l)
{
int i,j,k;
i = 0,j = 1,k = 0;
while(i < l && j < l) {
k = 0;
while(x[i+k] == x[j+k] && k < l) k++;
if(k == l) return l-abs(i-j)+i; //这一种利用到了循环节,不是很明白,时间:15ms
/*if(k == n) {
i = max(i,j);
j = i + 1;
continue; //时间:500+ms
}*/
if(x[i+k] > x[j+k])
if(j+k+1 > i) j += k+1;
else j = i+1;
else
if(i+k+1 > j) i += k+1;
else i = j+1;
}
if(j >= l) return i;
return j;
}
int main()
{
// freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
scanf("%s",s);
for(int i = 0;i < n; i++)
s[i+n] = s1[n-i-1] = s1[2*n-i-1] = s[i];
s[n*2] = s1[n*2] = '\0';
int pos1 = getMaxStringPos(s,n);
int pos2 = getMaxnixuPos(s1,n);
for(int i = 0;i < n; i++) {
ans1[i] = s[(i+pos1)];
ans2[i] = s1[(i+pos2)];
}
ans1[n] = ans2[n] = '\0';
if(strcmp(ans1,ans2) > 0) printf("%d 0\n",pos1+1);
else if(strcmp(ans1,ans2) < 0) printf("%d 1\n",n-pos2);
else {
if(n-pos2-1 < pos1) printf("%d 1\n",n-pos2);
else printf("%d 0\n",pos1+1);
}
}
return 0;
}