HDU 3374 String Problem(最大最小表示+KMP)題解

題意:給你一個字符串,這個字符串可以這樣操作:把第一個字符放到最後一個形成一個新的字符串,記原式Rank爲1,每操作一步Rank+1,問你這樣操作得出的最小字典序的字符串的Rank和這樣的字符串有幾個,最大字典序的字符串的Rank和這樣的字符串有幾個。

思路:手動模擬操作複雜度O(n^2)果斷超時,引入一種專門計算此情況的方法,複雜度O(n)。

這裏只說最小表示:

我們先拿兩個指針i,j,分別指向s[0],s[1],將k初始化爲0。然後我們循環計算s[i + k]是否等於s[j + k],直到找到一個不等的情況;如果找不到,說明當前已經是最小了。當不相等時,有兩種情況:

1.s[i + k]>s[j + k]說明以s[j + k]爲開頭字典序更小,i移動到該位置,置k = 0

2.s[i + k]<s[j + k]說明s[j]開頭不行,j移動到j + k + 1,置k = 0

最後返回min(i,j)

算幾個字符串可以用KMP的next數組計算最小循環節解決。

#include<iostream>
#include<algorithm>
const int maxn = 1000000+5;
const int INF = 0x3f3f3f3f;
using namespace std;
int fail[maxn];
char s[maxn],tmp[maxn];
void getFail(char *p){
     fail[0] = -1;
     int j = 0,k = -1;
     int len = strlen(p);
     while(j < len){
        if(k == -1 || p[j] == p[k]){
            fail[++j] = ++k;
        }
        else{
            k = fail[k];
        }
     }
}
int KMP(char *t,char *p){
    getFail(p);
    int i = 0,j = 0;
    int lent = strlen(t),lenp = strlen(p);
    while(i < lent){
        if(j == -1 || t[i] == p[j]){
            i++;
            j++;
            if(j == lenp) return 1;
        }
        else{
            j = fail[j];
        }
    }
    return 0;
}
int get_min(char *p){
    int len = strlen(p);
    int i = 0,j = 1,k = 0;
    while(i < len && j <len && k < len){
        int t = s[(i + k)%len] - s[(j + k)%len];
        if(t == 0) k++;
        else{
            if(t > 0)
                i += k + 1;
            else
                j += k + 1;
            if(i == j) j++;
            k = 0;
        }
    }
    return min(i,j);
}
int get_max(char *p){
    int len = strlen(p);
    int i = 0,j = 1,k = 0;
    while(i < len && j <len && k < len){
        int t = s[(i + k)%len] - s[(j + k)%len];
        if(t == 0) k++;
        else{
            if(t > 0)
                j += k + 1;
            else
                i += k + 1;
            if(i == j) j++;
            k = 0;
        }
    }
    return min(i,j);
}
int main(){
    while(scanf("%s",s) != EOF){
        int len = strlen(s);
        int MIN = get_min(s);
        int MAX = get_max(s);
        for(int i = 0,j = MIN;i < len;i++,j++){
            tmp[i] = s[j % len];
        }
        tmp[len] = '\0';
        getFail(tmp);
        int c = len - fail[len],ans;
        if(len % c == 0) ans = len / c;
        else ans = 1;
        printf("%d %d ",MIN + 1,ans);
        for(int i = 0,j = MAX;i < len;i++,j++){
            tmp[i] = s[j % len];
        }
        tmp[len] = '\0';
        getFail(tmp);
        c = len - fail[len];
        if(len % c == 0) ans = len / c;
        else ans = 1;
        printf("%d %d\n",MAX + 1,ans);
    }
    return 0;
}

 

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