头一次比赛中遇到最大(最小)表示法的题目
因为这个算法可以把字典序最大(最小)的串的最小的起始位置求出来,所以以为正着跑一遍 反着跑一遍compare一下就OK了。
其实反着跑的时候我是把字符串翻转的,所以求出来的其实是最大的起始位置 TAT
这样的话反着我们只能把这个长什么样求出来再KMP了 - -
WA了N次 还以为是题意理解错了 → →
#include <bits/stdc++.h>
using namespace std;
int n;
int f(char word[],int wlen,int flag) //最小最大表示法0、1
{
int i=0,j=1,k=0;
while(i<wlen&&j<wlen&&k<wlen)
{
int t=word[(i+k)%wlen]-word[(j+k)%wlen];
if(!t) k++;
else
{
if(flag==0)
{
if(t>0) i=i+k+1;
else j=j+k+1;
}
else
{
if(t>0) j=j+k+1;
else i=i+k+1;
}
if(i==j) j++;
k=0;
}
}
return i<j?i:j;
} //返回是从0开始,如果问第几个需加1
const int MAXN = 20100<<1;
char s[MAXN];
int compare(int a,int b)
{
for(int i=a,j=b,cnt=0;cnt<n;i++,j--,cnt++)
{
if(i==n)
i=0;
if(j<0)
j=n-1;
if(s[i]!=s[j])
return s[i]-s[j];
}
return 0;
}
struct KMP
{
int f[MAXN];
void getFail(char S[])
{
int i=0,j=-1;
int len=strlen(S);
f[0]=-1;
while (i<len)
{
if (j==-1||S[i]==S[j])
{
i++,j++;
f[i]=j;
}
else
j=f[j];
}
}
///Whether S is a substring of T
///Or whether T has S;
int beat(char T[],char S[])
{
int i=0,j=0;
int n=strlen(T);
int m=strlen(S);
getFail(S);
while(i<n)
{
if(j==-1||T[i]==S[j])
i++,j++;
else
j=f[j];
if(j==m)
return i;
}
return 0;
}
}soul;
char TS[MAXN<<1],S[MAXN];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
scanf("%s",s);
int ans1=f(s,n,1);
reverse(s,s+n);
int ans2=n-1-f(s,n,1);
reverse(s,s+n);
for(int i=ans2,cnt=0;cnt<n;i++,cnt++)
{
if(i==n)
i=0;
S[cnt]=s[i];
}
S[n]=0;
for(int i=0;i<(n<<1);i++)
TS[i]=s[i%n];
TS[n<<1]=0;
ans2=soul.beat(TS,S)-n;
int f=compare(ans1,ans2),p=1;
//printf("%d %d %d\n",ans1,ans2,f);
if(f<0)
p=2;
else if(f==0)
{
if(ans2<ans1)
p=2;
}
if(p==1)
printf("%d 0\n",ans1+1);
else
printf("%d 1\n",ans2+1);
}
return 0;
}