hdu P3374 String Problem

今天又在lyk大佬的博客学会了——最小表示法(异常激动
发篇题解纪念一下
说在前面:给luogu提个建议最小表示法的题太少了,都被hdu抢去了!!!



我们先看一下题目

看完后可以用一个字概括——,两个字——懵逼

在这里我提供题目大意:

输出最大和最小的是从哪一位开始的,同时输出最小循环节的个数。

由于本人懒于写字符串最小表示法,那么我们就来借鉴一下lykkk优秀总结

看完之后,显然我们就明白了许多

因为题目中让我们同时求出最大和最小的起始位置

所以我们不仅要来一遍最小表示法,还要来一遍最大表示法

其实这两种算法唯一的区别就是:

最小表示法中当str[i+k]>str[j+k]时,i+k的字典序比j+k的字典序大,那么我们就要抛弃当前以i为头的字符串,往后走即i+=k+1

最大表示法就是当str[i+k]<str[j+k]时,我们才要更新起点

各来一遍后,题目就完成了一半

至于KMP在这里的作用就是,利用next数组来求循环节,则次数=长度/循环节长度

说到这里,显然三个子函数足以解决这个问题了

我们最后只需要在主函数里根据题意输入输出即可

无代码,不成方圆

#include<bits/stdc++.h>
using namespace std;
const int N = 1100000;
int n;
char s[N];
int nxt[N];
void Kmp(int l){//用来求最小循环节的个数
    int j=0,k=nxt[0]=-1;
    while(j<l){
        if(k==-1 || s[j]==s[k]) nxt[++j]=++k;
        else k=nxt[k];
    }
}
int Min(char s[],int l){
    int i=0,j=1,k=0;
    while(i<l && j<l && k<l){
        if(s[(i+k)%l]==s[(j+k)%l]) k++;
        else if(s[(i+k)%l]>s[(j+k)%l]) i+=k+1,k=0;
        else j+=k+1,k=0;
        if(i==j) i++;
    }
    return min(i,j);
}
int Max(char s[],int n){
    int i=0,j=1,k=0;
    while(i<n && j<n && k<n){
        if(s[(i+k)%n]==s[(j+k)%n]) k++;
        else if(s[(i+k)%n]<s[(j+k)%n]) i+=k+1,k=0;//唯一的区别
        else j+=k+1,k=0;
        if(i==j) i++;
    }
    return min(i,j);
}
int main(){//常规操作
    while(scanf("%s",s)!=EOF){
        int len=strlen(s);
        Kmp(len);
        int maxn=Max(s,len),minn=Min(s,len);
        printf("%d %d %d %d
",minn+1,len/(len-nxt[len]),maxn+1,len/(len-nxt[len]));
    }
    return 0;
}

完结,撒花!

原文地址:https://www.cnblogs.com/xmex/p/10505906.html