您的位置:首页 > 其它

hdu 4333 Revolving Digits (扩展kmp)

2015-02-13 13:10 537 查看
题意:

给出一个数字的串,每次可以选择一个位置,然后把位置后面的放到这个串的最前面构成新的串。问构成的新的串中等于这个串,小于这个串,大于这个串的个数。

题解:

两种做法。

一种是直接应用扩展kmp,将原串复制一遍得到两倍的串,然后原串去匹配这个串。得到每个位置的最长前缀长度,如果长度extend[i]>=len说明相等,否则比较下个字符的大小。

第二种做法是从定义出发,扩展kmp的next数组存的就是串从i位置开始和本身的最大前缀,那么只要用next[i]就能进行比较。

第二种做法比较高效!

方法一:

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
//typedef long long lld;
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=2000010;
char str[maxn],s[maxn];
int next[maxn],extend[maxn];

void get_next(char T[],int len)
{
    int i=0;next[i]=-1;
    int j=-1;
    while(i<len)
    {
        if(j==-1||T[i]==T[j])
        {
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}

void get_extend(char T[],int len)
{
    int k=0;
    next[0]=len;
    while(k<len-1&&T[k]==T[k+1])k++;
    next[1]=k;
    k=1;
    for(int i=2;i<len;i++)
    {
        int p=k+next[k]-1,L=next[i-k];///p表示目前匹配的最大长度
        if(i+L-1>=p)///大于,要更新
        {
            int j=max(p-i+1,0);
            while(i+j<len&&T[i+j]==T[j])j++;
            next[i]=j;
            k=i;
        }
        else next[i]=L;
    }
}

void kmp_extend(char S[],char T[],int lenS,int lenT)
{
    int k=0;
    while(k<lenT&&k<lenS&&S[k]==T[k])k++;
    extend[0]=k;
    k=0;
    for(int i=1;i<lenS;i++)
    {
        int p=k+extend[k]-1,L=next[i-k];
        if(i+L-1>=p)
        {
            int j=max(p-i+1,0);
            while(i+j<lenS&&j<lenT&&S[i+j]==T[j])j++;
            extend[i]=j;
            k=i;
        }
        else extend[i]=L;
    }
}

int main()
{
    int T,L,E,G;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        scanf("%s",s);
        int len=strlen(s);
        strcpy(str,s);
        strcat(str,s);
        get_next(s,len);
        int cir=(len%(len-next[len]))==0?len/(len-next[len]):1;
        get_extend(s,len);
        kmp_extend(str,s,len*2,len);
        L=E=G=0;
        for(int i=0;i<len;i++)
        {
            if(extend[i]>=len) E++;
            else if(str[i+extend[i]]>s[extend[i]])G++;
            else L++;
        }
        printf("Case %d: %d %d %d\n",cas,L/cir,E/cir,G/cir);
    }
    return 0;
}
/**
addfg
addfg
addad
addad

34134

*/


方法二:

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
//typedef long long lld;
const int oo=0x3f3f3f3f;
//const lld OO=1LL<<61;
const int MOD=10007;
const int maxn=2000010;
char str[maxn],s[maxn];
int next[maxn],extend[maxn];

void get_next(char T[],int len)
{
    int i=0;next[i]=-1;
    int j=-1;
    while(i<len)
    {
        if(j==-1||T[i]==T[j])
        {
            i++;j++;
            next[i]=j;
        }
        else j=next[j];
    }
}

void get_extend(char T[],int len)
{
    int k=0;
    next[0]=len;
    while(k<len-1&&T[k]==T[k+1])k++;
    next[1]=k;
    k=1;
    for(int i=2;i<len;i++)
    {
        int p=k+next[k]-1,L=next[i-k];///p表示目前匹配的最大长度
        if(i+L-1>=p)///大于,要更新
        {
            int j=max(p-i+1,0);
            while(i+j<len&&T[i+j]==T[j])j++;
            next[i]=j;
            k=i;
        }
        else next[i]=L;
    }
}

int main()
{
    int T,L,E,G;
    scanf("%d",&T);
    for(int cas=1;cas<=T;cas++)
    {
        scanf("%s",s);
        int len=strlen(s);
        strcpy(str,s);
        strcat(str,s);
        get_next(s,len);
        int cir=(len%(len-next[len]))==0?len/(len-next[len]):1;
        get_extend(str,2*len);
        L=E=G=0;
        for(int i=0;i<len;i++)
        {
            if(next[i]>=len)E++;
            else if(str[i+next[i]]>str[next[i]])G++;
            else L++;
        }
        printf("Case %d: %d %d %d\n",cas,L/cir,E/cir,G/cir);
    }
    return 0;
}
/**
addfg
addfg
addad
addad

34134

*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: