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\n",minn+1,len/(len-nxt[len]),maxn+1,len/(len-nxt[len]));
    }
    return 0;
}

完結,撒花!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章