hdu 3374
最小表示+kmp
#include<iostream>
using namespace std;
const int maxn=2000005;
//最小表示+最大表示+KMP
//问题描述,求字典序最小的和字典序最大的位置,若多个取最左边的,并给出在这n个串中出现次数
//注意自身得情况,由于出始扩大了一倍,但自身只能算一次,这里要注意
char b[maxn];
char a[maxn];
int next[maxn];
int minshow(char *s)
{
int i=0,j=1,k=0,n=strlen(s);
while(i<n/2&&j<n/2&&k<n/2)
{
if(s[i+k]==s[j+k])k++;
else
{
if(s[i+k]>s[j+k])i+=(k+1);
else j+=(k+1);
if(i==j)j++;
k=0;
}
}
return min(i,j);
}
int maxshow(char *s)
{
int i=0,j=1,k=0,n=strlen(s);
while(i<n/2&&j<n/2&&k<n/2)
{
if(s[i+k]==s[j+k])k++;
else
{
if(s[i+k]<s[j+k])i+=(k+1);
else j+=(k+1);
if(i==j)j++;
k=0;
}
}
return min(i,j);
}
void slove(char *s)
{
int i,j,len=strlen(s);
next[0]=0;j=0;
for(i=1;i<len;i++)
{
while(j>0&&s[j]!=s[i])j=next[j-1];
if(s[j]==s[i])j++;
next[i]=j;
}
}
int kmp(char *a,char *b)
{
int i,j=0,lena=strlen(a),lenb=strlen(b),c=0;
for(i=0;i<lenb;i++)
{
while(j>0&&a[j]!=b[i])j=next[j-1];
if(a[j]==b[i])j++;
if(j==lena){j=next[j-1];c++;}
}
return c;
}
int main()
{
int i,j,k,n,mins,maxs,mint,maxt;
while(gets(b))
{
n=strlen(b);
for(i=0;i<n;i++)b[i+n]=b[i];
b[n+n]=0;
mins=minshow(b)+1;
for(i=0;i<n;i++)a[i]=b[i+mins-1];
a[n]=0;
slove(a);
mint=kmp(a,b+1);
maxs=maxshow(b)+1;
for(i=0;i<n;i++)a[i]=b[i+maxs-1];
a[n]=0;
slove(a);
maxt=kmp(a,b+1);
printf("%d %d %d %d\n",mins,mint,maxs,maxt);
}
return 0;
}
浙公网安备 33010602011771号