Hdu 3374 String Problem(KMP+字符串最大最小表示法)

Hdu 3374

题意:给你一个字符串,让你输出它移位后最小字典序的rank和循环节个数,最大字典序的rank和循环节个数。

题解:循环节好找,只要判断len%(len-nx[len])是否等于0,如果等于0说明含有循环节,则ans=len%(len-nx[len]),否则ans=1(即循环节为一整个字符串)。最小字典序和最大字典序的rank其实就是其首在原字符串的下标+1。做的时候去学习了一下最小最大表示法  感谢大佬的模版+讲解:https://www.cnblogs.com/cenariusxz/p/4903387.html

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e6+5;
using namespace std;
int nx[N];
char str[N<<1];
int len;
void getnx(int x){
    memset(nx,0,sizeof(nx));
    int k=-1,i=0;
    nx[0]=-1;
    while(i<x){
        if(k==-1||str[k]==str[i]){
            nx[++i]=++k;
        }
        else k=nx[k];
    }
}
int find_min_max(int flag){//0表示找最小 1表示找最大
    int i=0,j=1;//用i和j两个下标来表示两个字符串
    while(i<len&&j<len){
        int k=0;
        while(str[i+k]==str[j+k])k++;//不断比较直到比较完长度为l的串或两个子串不相等
        if(k>=len)return min(i,j);//当比较长度大于等于len的时候,返回最小的首下标
        if(flag==0){
            if(str[i+k]>str[j+k])i=max(i+k+1,j+1);//i串比j串大,那么i到i+k中的串都比j串大,i可以直接移动到i+k+1位置,而起始位置比j小的肯定都在j移动过程中比较过,所以i可以直接移动到j+1位置,因此取这两值的最大值(这句话是复制过来的~~~)
            else j=max(j+k+1,i+1);
        }
        else{
            if(str[i+k]<str[j+k])i=max(i+k+1,j+1);
            else j=max(j+k+1,i+1);
        }
    }
    return min(i,j);
}
int main(){
    while(~scanf("%s",str)){
        len=strlen(str);
        getnx(len);
        for(int i=0;i<len;i++)str[i+len]=str[i];//将字符串复制一倍
        int ans;
        if(len%(len-nx[len])==0)ans=len/(len-nx[len]);
        else ans=1;
        int a=find_min_max(0)+1;
        int b=find_min_max(1)+1;
        printf("%d %d %d %d
",a,ans,b,ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Mrleon/p/8414453.html