HDU 3374 最小/大表示法+KMP

 

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374

题意:给定一个串s,该串有strlen(s)个循环同构串,要求输出字典序最小的同构串的下标,字典序最小的出现次数,最大的同构串的下标,字典中最大的出现次数。

思路:对于求循环同构的字典序最小可以用最小表示法求得,最大也是一样。然后设ds为字符串s+s。然后就可以用KMP求最小串在ds出现的次数和最大串出现的次数了。

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
const int MAXN = 1000000 + 5;
typedef long long int LL;
#define INF 0x3f3f3f3f
int Representation(char *s,int l,bool flag){ //flag:0 最小表示法  flag:1 最大表示法
    int i = 0, j = 1, k = 0;
    while (i < l&&j < l&&k < l){
        int li, lj;
        li = (i + k) >= l ? i + k - l : i + k;
        lj = (j + k) >= l ? j + k - l : j + k;
        if (s[li] == s[lj]){
            k++;
        }
        else{
            if (!flag){
                if (s[li]>s[lj]){
                    i = i + k + 1;
                }
                else{
                    j = j + k + 1;
                }
            }
            else{
                if (s[li]<s[lj]){
                    i = i + k + 1;
                }
                else{
                    j = j + k + 1;
                }
            }
            if (i == j){
                j++;
            }
            k = 0;
        }
    }
    return i < j ? i : j;
}
int Next[MAXN];
void getnext(char *s,int lens){ //KMP的next数组
    int j, k;
    j = 0; k = -1; Next[0] = -1;
    while (j < lens){
        if (k == -1 || s[j] == s[k]){
            Next[++j] = ++k;
        }
        else{
            k = Next[k];
        }
    }
}
int KMP_Count(char *s,int lens,char *t,int lent){ //计算t串在s串中出现的次数
    int ans = 0, j = 0;
    memset(Next, 0, sizeof(Next));
    getnext(t,lent);
    for (int i = 0; i < lens; i++){
        while (j>0 && s[i] != t[j]){
            j = Next[j];
        }
        if (s[i] == t[j]){
            j++;
        }
        if (j == lent){
            ans++;
            j = Next[j];
        }
    }
    return ans;
}
char str[MAXN], dstr[MAXN*2],minstr[MAXN],maxstr[MAXN];
//原串,原串*2后的串,字典序最小的串,字典序最大的串
int main()
{
    while (~scanf("%s", str)){
        int len = strlen(str);
        for (int i = 0; i < len * 2 ; i++){
            dstr[i] = str[(i%len)];
        }
        //计算最小
        int minstart = Representation(str, len,0);
        for (int i = 0; i < len; i++){
            minstr[i] = str[(i + minstart) % len];
        }
        int mincount = KMP_Count(dstr, len * 2 - 1, minstr, len);
        //计算最大
        int maxstart = Representation(str, len,1);
        for (int i = 0; i < len; i++){
            maxstr[i] = str[(i + maxstart) % len];
        }
        int maxcount = KMP_Count(dstr, len * 2 - 1, maxstr, len);
        printf("%d %d %d %d\n", minstart + 1,mincount , maxstart + 1, maxcount);
    }
    return 0;
}

 

posted @ 2016-06-22 23:24  キリト  阅读(164)  评论(0编辑  收藏  举报