链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333

题意:给以数字字符串,移动最后若干位到最前边,统计得到的数字有多少比原来大,有多少和原来同样,有多少比原来的小。

思路:拓展KMP中的next数组标记的是子串和母串的公共前缀的长度,要将字符串长度变成原来二倍,这样假设变换后不是全然同样的数字也即公共前缀长度大于等于字符串长度,那么字母串公共前缀的下一位的大小比較就是题目所要求的比較。因为同样的数字串仅仅算一次,则仅仅要统计比較第一个“循环节”里的改变数字串就可以。

资料:【转】扩展KMP http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html

扩展KMP:
    给出模板串A和子串B,长度分别为lenA和lenB,要求在线性时间内,对于每一个A[i](0<=i<lenA),
 
    求出A[i..lenA-1]与B的最长公共前缀长度,记为ex[i](或者说,ex[i]为满足A[i..i+z-1]==B[0..z-1]的最大的z值)。
 
    扩展KMP能够用来解决非常多字符串问题,如求一个字符串的最长回文子串和最长反复子串。


【算法】

    
    设next[i]为满足B[i..i+z-1]==B[0..z-1]的最大的z值(也就是B的自身匹配)。设眼下next[0..lenB-1]与ex[0..i-1]均已求出,要用它们来求ex[i]的值。


    设p为眼下A串中匹配到的最远位置,k为让其匹配到最远位置的值(或者说,k是在0<=i0<i的全部i0值中,使i0+ex[i0]-1的值最大的一个,p为这个最大值,即k+ex[k]-1),
    
    显然,p之后的全部位都是未知的,也就是眼下还无法知道A[p+1..lenA-1]中的不论什么一位和B的不论什么一位是否相等。

    
    依据ex的定义可得,A[k..p]==B[0..p-k],由于i>k,所以又有A[i..p]==B[i-k..p-k],设L=next[i-k],则依据next的定义有B[0..L-1]==B[i-k..i-k+L-1]。考虑i-k+L-1与p-k的关系:

    
    (1)i-k+L-1<p-k,即i+L<=p。这时,由A[i..p]==B[i-k..p-k]能够得到A[i..i+L-1]==B[i-k..i-k+L-1],又由于B[0..L-1]==B[i-k..i-k+L-1]所以A[i..i+L-1]==B[0..L-1],这就说明ex[i]>=L。又由于next的定义可得,
 
A[i+L]必定不等于B[L](否则A[i..i+L]==B[0..L],由于i+L<=p,所以A[i..i+L]==B[i-k..i-k+L],这样B[0..L]==B[i-k..i-k+L],故next[i-k]的值应为L+1或更大),这样,能够直接得到ex[i]=L!

    
    (2)i+k-L+1>=p-k,即i+L>p。这时,首先能够知道A[i..p]和B[0..p-i]是相等的(由于A[i..p]==B[i-k..p-k],而i+k-L+1>=p-k,由B[0..L-1]==B[i-k..i-k+L-1]可得B[0..p-i]==B[i-k..p-k],即A[i..p]==B[0..p-i]),然
 
后,对于A[p+1]和B[p-i+1]是否相等,眼下是不知道的(由于前面已经说过,p是眼下A串中匹配到的最远位置,在p之后无法知道不论什么一位的匹配信息),因此,要从A[p+1]与B[p-i+1]開始往后继续匹配(设j为眼下
 
B的匹配位置的下标,一開始j=p-i+1,每次比較A[i+j]与B[j]是否相等,直到不相等或者越界为止,此时的j值就是ex[i]的值)。在这样的情况下,p的值必定会得到延伸,因此更新k和p的值。
    
    边界:ex[0]的值须要预先求出,然后将初始的k设为0,p设为ex[0]-1。
 
对于求next数组,也是“自身匹配”,类似KMP的方法处理就可以。唯一的不同点也在边界上:能够直接知道next[0]=lenB,next[1]的值预先求出,然后初始k=1,p=ex[1]。



须要严重注意的是,在上述的情况(2)中,本该从A[p+1]与B[p-i+1]開始匹配,可是,若p+1<i,也就是p-i+1<0(这样的情况是有可能发生的,当ex[i-1]=0,且前面的ex值都没有延伸到i及以后的时候)的话,须要将A、B的下标都加1(由于此时p必定等于i-2,假设A、B的下标用两个变量x、y控制的话,x和y都要加1)!!


【时间复杂度分析】


    在KMP和扩展KMP中,无论是A串还是B串,其匹配位置都是单调递增的,故总时间复杂度是线性的,都为O(lenA + lenB)(仅仅是扩展KMP比KMP的常数更大一些)。


【应用】


    KMP和扩展KMP在解决字符串问题中有大用。非常多看上去非常猥琐的字符串问题,都能够归结到这两种算法之中。另外,这里的“字符串”能够延伸为一切类型的数组,而不不过字符数组。
代码:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int ext[1000005*2];
char ss[1000005*2];
void getnext(char *T,int *next)
{
int i,length = strlen(T);
next[0] = length;
for(i = 0; i<length-1 && T[i]==T[i+1]; i++);
next[1] = i;
int a = 1;
for(int k = 2; k < length; k++)
{
int p = a+next[a]-1, L = next[k-a];
if( (k-1)+L >= p )
{
int j = (p-k+1)>0? (p-k+1) : 0;
while(k+j<length && T[k+j]==T[j]) j++;
next[k] = j, a = k;
}
else next[k] = L;
}
}
int main()
{
int tot,a,b,c;
scanf("%d",&tot);
for(int ii=1; ii<=tot; ii++)
{
a=b=c=0;
scanf("%s",ss);
int len=strlen(ss);
for(int i=len; i<len*2; i++)
ss[i]=ss[i-len];
getnext(ss,ext);
ss[2*len]='\0';
int k=len;
for(int i=1;i<=len;i++)
{
if(i+ext[i]>=len)
{
k=len%i?len:i;
break;
}
}
for(int i=0; i<k; i++)
{
if(ext[i]>=len)
b++;
else if(ss[i+ext[i]]>ss[ext[i]])
a++;
else c++;
}
printf("Case %d: %d %d %d\n",ii,c,b,a);
}
return 0;
}

HDU 4333 Revolving Digits 扩展KMP的更多相关文章

  1. HDU 4333 Revolving Digits [扩展KMP]【学习笔记】

    题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数. SAM乱搞失败 当然要先变SS了 然后考虑每个后缀前长为n个字符,把它跟S比较就行了 如 ...

  2. HDU 4333 Revolving Digits 扩张KMP

    标题来源:HDU 4333 Revolving Digits 意甲冠军:求一个数字环路移动少于不同数量 等同 于的数字 思路:扩展KMP求出S[i..j]等于S[0..j-i]的最长前缀 推断 nex ...

  3. 字符串(扩展KMP):HDU 4333 Revolving Digits

    Revolving Digits Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  4. HDU - 4333 Revolving Digits(扩展KMP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4333 题意 一个数字,依次将第一位放到最后一位,问小于本身的数的个数及等于本身的个数和大于本身的个数,但是要注意 ...

  5. 扩展KMP - HDU 4333 Revolving Digits

    Revolving Digits Problem's Link Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. ...

  6. 【扩展kmp+最小循环节】HDU 4333 Revolving Digits

    http://acm.hdu.edu.cn/showproblem.php?pid=4333 [题意] 给定一个数字<=10^100000,每次将该数的第一位放到放到最后一位,求所有组成的不同的 ...

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

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

  8. hdu4333 Revolving Digits(扩展kmp)

    Revolving Digits Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  9. Hdu 4333 Revolving Digits(Exkmp)

    Revolving Digits Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...

随机推荐

  1. pyqt字符串分离开,放入列表中

    string1 = ''''' the stirng Has many line In THE fIle ''' list_of_string = string1.split() print list ...

  2. To Miss Our Children Time(dp)

    To Miss Our Children Time Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Jav ...

  3. 达到XML简单的动态配置

    今天写的XML相关内容:随着上述眼前的小项目(等级类别)由于地图每个级别.因此,让他动态读取XML内容,这样的变化只能看到XML档. 简单的想法:第一次使用UserDefault类写入文件 UserD ...

  4. poi读写Excel文件

    jxl 只有excel基本的操作,代码操作比较方便,一般使用jxl就够了,对图片支持较好 poi功能比jxl强大但是比较吃内存,支持计算公式        关于jxl具体可以参考    http:// ...

  5. JavaScript ----------------- 寄生式继承

    寄生式继承 寄生式继承是于原型式继承紧密相关的一种思路.寄生式基础的思路与寄生构造函数和工厂模式类似,既创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再像真地是它做了所有工作一 ...

  6. js如何关闭当前页,而不弹出提示框

    //关闭当前页面,并且打开新页面,(不提示) function closeWinAndOpen(url) { //利用随机数处理WinName var sWinName = "LR" ...

  7. 提示框的优化之自定义Toast组件之(二)Toast组件的业务逻辑实现

    在java下org.socrates.mydiary.activity下LoginActivity下自定义一个方法showCustomerToast()  public class LoginAct ...

  8. SQL SERVER 清空日志

    DUMP TRANSACTION [TBNAME] WITH NO_LOGBACKUP LOG [TBNAME] WITH NO_LOGDBCC SHRINKDATABASE([TBNAME]) 1. ...

  9. java菜鸟篇<一> 对JsonObject 和JsonArray知识点理解

    今天遇到从前台拿值(json数组格式),从request里边取值,然后经过一系列的处理方式,在用request返回去 1.先把request里的值赋值给String string类型的变量 2.因为前 ...

  10. 图的广度、深度优先遍历 C语言

    以下是老师作为数据结构课的作业的要求,没有什么实际用处和可以探讨和总结的的地方,所以简单代码直接展示. 宽度优先遍历: #include<cstdio> #include<iostr ...