hdu P3374 String Problem

今天又在lyk大佬的博客學會了——最小表示法(異常激動
發篇題解記念一下
說在前面:給luogu提個建議最小表示法的題太少了,都被hdu搶去了!!!php



咱們先看一下題目html

 

看完後能夠用一個字歸納——,兩個字——懵逼c++

在這裏我提供題目大意:算法

輸出最大和最小的是從哪一位開始的,同時輸出最小循環節的個數。數組

因爲本人懶於寫字符串最小表示法,那麼咱們就來借鑑一下lykkk優秀總結函數

看完以後,顯然咱們就明白了許多spa

由於題目中讓咱們同時求出最大和最小的起始位置code

因此咱們不只要來一遍最小表示法,還要來一遍最大表示法htm

其實這兩種算法惟一的區別就是:blog

最小表示法中當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\n",minn+1,len/(len-nxt[len]),maxn+1,len/(len-nxt[len]));
    }
    return 0;
}

完結,撒花!

相關文章
相關標籤/搜索