HDU 3374
题意:求出字典序最小串,最子串的位置和个数(字符串是头尾相连的)
思路:个数的话只看循环节个数就行了,但是最小串,最大串,怎么找出位置呢?O(n),主角登场:最小表示法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+5;
int len,nxt[maxn],cnt;
char a[maxn];
void kmp_pre1()
{
int i=0,j=nxt[0]=-1;
while(i<len)
{
while(j!=-1&&a[i]!=a[j])
j=nxt[j];
nxt[++i]=++j;
}
}
int getmin(char *s)
{
int n=cnt;
int i=0,j=1,k=0,t;
while(i<n && j<n && k<n)
{
t=s[(i+k)%n]-s[(j+k)%n];
if (!t) k++;
else
{
if (t>0) i+=k+1;
else j+=k+1;
if (i==j) j++;
k=0;
}
}
return i<j?i:j;
}
int getmax(char *s)
{
int n=cnt;
int i=0,j=1,k=0,t;
while(i<n && j<n && k<n)
{
t=s[(i+k)%n]-s[(j+k)%n];
if (!t) k++;
else
{
if (t>0) j+=k+1;
else i+=k+1;
if (i==j) j++;
k=0;
}
}
return i<j?i:j;
}
int main()
{
while(~scanf("%s",a))
{
len=strlen(a);
int st=1,ed=len,n=len;
kmp_pre1();
if(n%(n-nxt[n])==0)
cnt=(n-nxt[n]);
else
cnt=len;
int pos1=1,pos2=1;
pos1+=getmin(a);
pos2+=getmax(a);
if(n%(n-nxt[n])==0)
printf("%d %d %d %d\n",pos1,n/(n-nxt[n]),pos2,n/(n-nxt[n]));
else
printf("%d %d %d %d\n",pos1,st,pos2,st);
}
}