hdu3374
题意:
给你一个字符串,问这个字符串经过移动后的字典序最小的字符串的首字符位置和字典序最大的字符串的首字符的位置,和能出现多少次最小字典序的字符串和最大字典序的字符串
题解:
利用最小表示法与最大表示法O(n)复杂度求出最小字典序和最大字典序串出现位置,然后利用kmp求出next,利用next数组性质求出循环节次数,因为最小和最大字典序串出现次数等于循环节次数(因为有几个循环节,我们就会有几个最小串或最大串的起始点)
#include<bits/stdc++.h>
using namespace std;
const int maxn=2000005;
int nxt[maxn];
char s[maxn];
int n;
int getmin()
{
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n){
int t=s[(i+k)%n]-s[(j+k)%n];
if(t==0)k++;
else{
if(t>0) i=i+k+1;
else j=j+k+1;
if(i==j) j++;
k=0;
}
}
return min(i,j);
}
int getmax()
{
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n){
int t=s[(i+k)%n]-s[(j+k)%n];
if(t==0) k++;
else{
if(t>0)j=j+k+1;
else i=i+k+1;
if(i==j)j++;
k=0;
}
}
return min(i,j);
}
void getnxt()//注意:不同的getnext写法要注意区分,否则就会错
{
int i=0,j=-1;
nxt[0]=-1;
while(i<n){
if(j==-1||s[i]==s[j]){
i++;
j++;
nxt[i]=j;
}
else{
j=nxt[j];
}
}
}
void GetNex(){
memset(nxt,0,sizeof(nxt));
int j=-1;
for(int i=0;s[i];i++){
while(s[i]!=s[j+1]&&j!=-1)j=nxt[j];
if(s[i]==s[j+1]&&i!=0)j++;
nxt[i]=j;
}
}
int main()
{
while(scanf("%s",s)!=EOF){
n=strlen(s);
int mi=getmin();
int mx=getmax();
getnxt();
int sum=0;
if(s[n-1]==s[nxt[n-1]]){
sum=n-(nxt[n-1]+1);
}
else{
sum=n-(nxt[n-1]);
}
if(n==1){
printf("1 1 1 1\n");
}
else{
int ko=1;
if(n%sum==0){
ko=n/sum;
}
else{
ko=1;
}
printf("%d %d %d %d\n",mi+1,ko,mx+1,ko);
}
}
return 0;
}