hdu 3374 String Problem (最小表示法+kmp next[])

小記:這題蠻好,比較有意思


思路:字母序最小和最大的串,我們可以用最小表示法和最大表示法解決,比較簡單。參考

然後就是出現的次數,這個解決方案可以直接利用kmp的next數組直接暴力求取最大和最小的出現的次數。

但是這裏面卻還是有特性的。我們來看:

我們的next數組的含義就是: next[j] 表示 字符串S,S[0,j-1]的前綴和後綴的相等的最長長度。這一點要好好理解下。畢竟也是kmp的精髓

然後我們來看next[len]的意義,len是S的長度。next[len]就意味着,S的前綴和後綴的相等部分的最長長度。

然後再看len - next[len], 這個值是非常有意義的,假設爲sublen。 它代表着去除那個最長前綴所剩下的字符的個數(或者後綴,但值都是一樣的),

而這個值就是關鍵所在,如果它能被len整除,就意味着,整個S有len/sublen個相同的sublen,注意是相同是從sublen的始到終每一塊對應的字符都是一樣的。

這--------------- ---  假設是分開的18個字符,但是代表字符串S,空格不算,爲了區分,做個例子

前面15個代表next[len]值, sublen就等於3, 而根據next數組的意義,顯然

--- ---------------  這個後綴是和前面那個前綴相同的, 那麼最後那一部分肯定是相同的,因此

最後3個字符,和倒數6-4,這個3個字符也是相同的,同理可以一直往前延續,所以結果就出來了

當len/sublen可以整除時,結果是無論從那一個字符開始,它循環表示的串 都會出現len/sublen次。

而不能整除時,因爲有某些字符擋在哪裏,你循環表示時,就會打亂你的次序,因此無論從那一個字符開始,它循環表示的串出現的次數都是1次。


答案顯而易見。這樣是不是簡化了很多。


代碼:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <set>
#include <vector>
#include <stack>
#include <queue>
#include <algorithm>

using namespace std;

#define mst(a,b) memset(a,b,sizeof(a))
#define REP(a,b,c) for(int a = b; a < c; ++a)
#define eps 10e-8

const int MAX_ = 1000010;
const int N = 500000;
const int INF = 0x7fffffff;

char str[MAX_], str1[MAX_];
int hash[MAX_];
int next[MAX_];
int a[MAX_];
map<string, int> mp;

void compute_next(char substr[]) {
    int i,j, len;
    len = strlen(substr);
    i=0;
    next[0]=-1;
    j=-1;
    while(i < len) {
        if(j == -1 || substr[i] == substr[j]) {
            i++;
            j++;
            //修正的地方就發生下面這4行
            if(substr[i] != substr[j] )
                next[i] = j;
            else
                next[i] = next[j];
        } else {
            j = next[j];
        }

    }
}

int Minimize(char str[]) {
    int i= 0, j= 1, len, k =0;
    len = strlen(str);
    while(i < len && j < len && k < len) {
        int t = str[(i+k)%len] - str[(j+k)%len];
        if(!t)++k;
        else {
            if(t > 0)i = i+k+1;
            else j = j+ k + 1;
            if(i == j)++j;
            k = 0;
        }
    }
    return i>j?j:i;
}

int Maximize(char str[]) {
    int i= 0, j= 1, len, k =0;
    len = strlen(str);
    while(i < len && j < len && k < len) {
        int t = str[(i+k)%len] - str[(j+k)%len];
        if(!t)++k;
        else {
            if(t < 0)i = i+k+1;
            else j = j+ k + 1;
            if(i == j)++j;
            k = 0;
        }
    }
    return i>j?j:i;
}



int main() {
    int T, n, m, numa = 0, numb = 0,ans;
    bool flag = 0;
    string s = "";


    while(~scanf("%s", str)) {
        numa = Minimize(str);
        numb = Maximize(str);
        compute_next(str);
        int len = strlen(str);

        m = len - next[len];
        ans = len%m?1:len/m;
        printf("%d %d %d %d\n",numa+1,ans,numb+1, ans);
    }
    return 0;
}


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