hdu 5442 Favorite Donut(最大表示法+kmp)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5442

解题思路:

题目大意:

有一个len长度的环,问有没有最大的长度为len的串在这个环里。

如果有的话,且只有一个,输出其开头的下标,下标从1 开始,再输出0 表示顺时针1表示逆时针

如果多个,输出开头下标最小的那个。

还有如果,就是顺时针,逆时针一样的情况,输出下标 0。

算法思想:

最小表示法模板:

http://blog.csdn.net/piaocoder/article/details/48447193

首先正序直接用最大表示法 ,可以得到最大字典序,最小下标的开头位置。

然后逆序就把串反下,用最大表示法,可以得到最大字典序,也是下标最小的开头位置,但是因为颠倒了,这里的下标是倒序的,

所以下标其实是最大的。 但是我们已经得到 最大 字典序的串了, 所以接下来把反的串重复一遍,可以用kmp找其中相同串最大

起始位置。 

然后把两个最大字典序的串比较下大小。正序大输出正序,逆序大出逆序,相等则输出标号最小的。

AC代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;
const int maxn = 20005;

int n,Next[maxn];
char S[maxn],T[maxn],A[maxn],B[maxn];

int maxRepresstation(char *s){
    int len = n;
    int i = 0,j = 1,k = 0;
    while(i<len && j<len && k<len){
        int tmp = s[(i+k)%len]-s[(j+k)%len];
        if(tmp == 0)
            k++;
        else{
            if(tmp < 0)//最大表示法
                i += k+1;
            else
                j += k+1;
            if(i == j)
                j++;
            k = 0;
        }
    }
    return min(i,j);
}

void get(char* t,char* s,int a,int n){
    for (int i = 0; i < n; i++)
        t[i] = s[(a+i)%n];
    t[n] = '\0';
}

bool judge(int a,int b){
    int k = strcmp(A,B);
    if (k != 0)
        return k > 0;
    return
        a <= b;
}

void getNext(char *p){
    int j = 0,k = -1;
    Next[0] = -1;
    while(j < n){
        if(k==-1 || p[j]==p[k]){
            j++; k++;
            Next[j] = k;
        }
        else
            k = Next[k];
    }
}

int solve (char* s){
    getNext(s);
    if (n % (n - Next[n]))
        return n;
    else
        return n - Next[n];
}

int main(){
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%s",&n,S);
        int k = solve(S);
        int a = maxRepresstation(S);
        get(A,S,a,n);
        reverse(S,S + n);
        int b = maxRepresstation(S);
        get(B,S,b,n);
        a %= k;
        b = (n - b - 1) % k;
        if(judge(a,b))
            printf("%d 0\n",a + 1);
        else
            printf("%d 1\n",b + 1);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值