码迷,mamicode.com
首页 > 其他好文 > 详细

HDU - 4333 Revolving Digits(拓展kmp+最小循环节)

时间:2015-11-06 21:03:37      阅读:248      评论:0      收藏:0      [点我收藏+]

标签:

1、给一个数字字符串s,可以把它的最后一个字符放到最前面变为另一个数字,直到又变为原来的s。求这个过程中比原来的数字小的、相等的、大的数字各有多少。

例如:字符串123,变换过程:123 -> 312 -> 231 -> 123

因为:312>123, 231>123, 123=123

所以答案是:0 1 2

2、令str1=s,str2=s+s,然后str1作为子串,str2作为主串,进行扩展kmp求出str2[i...len2-1]与str1[0...len1-1]的最长公共前缀。当公共前缀==len1时,两个数相等;否则,只须比较公共前缀后的下一个字符就能判断大小了。

注意当中有重复的情况,只有当s有循环节的时候才会出现,先求出s的最小循环节,然后用s的长度除以最小循环节得到循环节的个数,将3个结果都除以循环节个数即可。

3、

技术分享
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;

#define MaxSize 200005

int _next[MaxSize],extend[MaxSize];

//扩展kmp
//next[i]:x[i...m-1]与x[0...m-1]的最长公公前缀
//extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀
void pre_EKMP(char x[],int m,int _next[]){//m长度
    _next[0]=m;
    int j=0;
    while(j+1<m&&x[j]==x[j+1])j++;
    _next[1]=j;
    int k=1;
    for(int i=2;i<m;i++){
        int p=_next[k]+k-1;
        int L=_next[i-k];
        if(i+L<p+1)_next[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<m&&x[i+j]==x[j])j++;
            _next[i]=j;
            k=i;
        }
    }
}

void EKMP(char x[],int m,char y[],int n,int _next[],int extend[]){//x子串,m子串长度,y主串,n主串长度
    pre_EKMP(x,m,_next);
    int j=0;
    while(j<n&&j<m&&x[j]==y[j])j++;
    extend[0]=j;
    int k=0;
    for(int i=1;i<n;i++){
        int p=extend[k]+k-1;
        int L=_next[i-k];
        if(i+L<p+1)extend[i]=L;
        else{
            j=max(0,p-i+1);
            while(i+j<n&&j<m&&y[i+j]==x[j])j++;
            extend[i]=j;
            k=i;
        }
    }
}
/*
子串  :a b a b
主串  :a b a b a c
next  :4 0 2 0
extend:4 0 3 0 1 0
*/
void GetNext(char t[]){//求next数组
    int j,k,len;
    j=0;//从0开始,首先求_next[1]
    k=-1;//比较指针
    _next[0]=-1;//初始值-1
    len=strlen(t);
    while(j<len){
        if(k==-1||t[j]==t[k]){//指针到头了,或者相等
            ++j;
            ++k;
            _next[j]=k;//此句可由优化替代
            /*优化(求匹配位置时可用)
            if(t[j]!=t[k])_next[j]=k;
            else _next[j]=_next[k];
            //*/
        }
        else k=_next[k];
    }
}
int main(){
    char str1[100005],str2[200005];//子串,主串
    int i,j,len1,len2;//子串长度,主串长度
    int T;
    int sumL,sumE,sumG;
    scanf("%d",&T);
    for(i=1;i<=T;++i){
        sumL=sumE=sumG=0;
        scanf("%s",str1);
        strcpy(str2,str1);
        strcat(str2,str1);
        len1=strlen(str1);
        len2=strlen(str2);
        EKMP(str1,len1,str2,len2,_next,extend);
        for(j=0;j<len1;++j){
            if(extend[j]==len1)++sumE;
            else if(str2[j+extend[j]]<str1[extend[j]])++sumL;
            else ++sumG;
        }
        GetNext(str1);
        int repetend=len1-_next[len1];//最小循环节
        int numR;//循环节的个数
        if(len1%repetend==0)numR=len1/repetend;
        else numR=1;
        printf("Case %d: %d %d %d\n",i,sumL/numR,sumE/numR,sumG/numR);
    }

    return 0;
}
View Code

 

HDU - 4333 Revolving Digits(拓展kmp+最小循环节)

标签:

原文地址:http://www.cnblogs.com/bofengyu/p/4943586.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!