HDU 5442 Favorite Donut 最大最小表示法+KMP

题意:给定长度为n的字符串,字符串构成一个环,然后找出来一个位置,以这个位置开始,顺时针或者逆时针构成的字符串字典序最大,求最小的位置,如果同一位置顺逆时针都一样的话优先顺时针。

当时直接套最大最小表示法模板WA了...发现是带有循环节的地方过不去,因为处理逆时针的时候我把字符串逆置了,然后对于abcabc,逆置之后是cbacba,最大表示法求出的位置是1,在转回来是6..但是答案是逆时针的3...赛后然后窝打出next数组,单纯判断一下是否逆置的串是包含循环节的串,但是没过- -套了一个kmp才过...把逆置的串复制一遍拼接到后面,然后再找个串中找出逆置串所在的最大位置...

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<stack>
using namespace std;
#define MAXN 103000
#define ll long long
char t[120000],p[120000];
int nex[120000];
char xx[MAXN],yy[MAXN];
void getnext(char *t,int m)
{
    int i,j;
    i=0;j=-1;
    nex[0]=-1;
    while(i<m)
    {
        if(j==-1||t[i]==t[j])  nex[++i]=++j;
        else j=nex[j];
    }
}
int kmp(char *s,char *t)
{
    int n,m,i,j;
    i=j=0;
    int ans=0;
    n=strlen(s);
    m=strlen(t);
   // puts(s);
  //  puts(t);
    getnext(t,m);
    while(i<n-1&&j<m)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;j++;
        }
        else j=nex[j];
        if(j==m)
        {
            ans=max(ans,i-m);
            j=nex[j];
            //return i-m+1;
        }
    }

   // printf("%d\n",ans);
    return ans;
}
int minmaxstring(char *t,int m)
{
    int i,j,k;
    i=k=0;
    j=1;
    while(k<m&&i<m&&j<m)
    {
        int tep=t[(i+k)%m]-t[(j+k)%m];
        if(tep==0) k++;
        else
        {
            if(tep<0) j=(j+k+1);
            else i=(i+k+1);
            if(i==j) j++;
            k=0;
        }
    }
    return min(i,j);
}

int n;
int bj(int a,int b)
{
    for(int i=0; i<n; i++)
    {
        if(t[a]<p[b])
            return 1;
        else if(t[a]>p[b])
            return -1;
        a=(a+1)%n;
        b=(b+1)%n;
    }
    return 0;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(t,0,sizeof(t));
        memset(p,0,sizeof(p));
        scanf("%d",&n);
        scanf("%s",t);
        for(int i=0; i<n; i++)
        {
            t[i]=(25-t[i]+'a')+'a';
        }
        int ans1=minmaxstring(t,n);

        for(int i=n-1,j=0; i>=0; i--,j++)
            p[j]=t[i];
        int ans2=minmaxstring(p,n);
        int tep=ans2;
        for(int i=0;i<n;i++)
        {
            xx[i]=xx[n+i]=p[i];
            yy[i]=p[tep];
            tep=(tep+1)%n;
        }
        yy[n]='\0';
        xx[n+n]='\0';
        ans2=kmp(xx,yy);
        int c=bj(ans1,ans2);
        ans2=n-1-ans2;
        if(c>0)
            printf("%d 0\n",ans1+1);
        else if(c<0)
            printf("%d 1\n",ans2+1);
        else
        {
            if(ans1<=ans2)
                printf("%d 0\n",ans1+1);
            else
                printf("%d 1\n",ans2+1);
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值