hdu 4333 不错的EKMP+KMP

题意就不说了

把串头尾相接    当做文本串      把原串作模式串  进行EKMP      对每个i   若果extand【i】》=len则相等     否则比较下一位即可判断是大于还是小于   对于题意所说的不同的数   就是让你去判断原串是不是回文串     这就得用到KMP里面的next数组了      具体看代码:   最后用得出来的去除以循环次数就行了

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

char str1[200010],str2[200010];
int next[100010],extand[200010],knext[100010];
int kmpnext(char str[],int len)
{
    memset(knext,0,sizeof(knext));
    knext[0]=-1;
    int j=0,k=-1;
    while(j<len)
    {
        if(k==-1||str[j]==str[k])
        {
            ++j;
            ++k;
            knext[j]=k;
        }
        else k=knext[k];
    }
    return 0;

}
int get_next(char str[],int len)
{
    memset(next,0,sizeof(next));
    next[0]=len;
    int a=0;
    while(a<len&&str[a]==str[a+1]) a++;
    next[1]=a;
    a=1;
    for(int i=2;i<len;i++)
    {
        int p=a+next[a]-1;
        int L=next[i-a];
        if(L+i-1>=p)
        {
            int j=p-i+1>0?p-i+1:0;
            while(i+j<len&&str[i+j]==str[j]) j++;
            next[i]=j;
            a=i;
        }
        else next[i]=L;
    }
    return 0;
}
int EKMP(char str1[],char str2[])
{
    int len=strlen(str2);
    get_next(str2,len);
    int a=0;
    while(a<len&&str1[a]==str2[a]) a++;
    extand[0]=a;
    a=0;
    for(int i=1;i<2*len;i++)
    {
        int p=a+extand[a]-1;
        int L=next[i-a];
        if(L+i-1>=p)
        {
            int j=p-i+1>0?p-i+1:0;
            while(i+j<2*len&&j<len&&str1[i+j]==str2[j]) j++;
            extand[i]=j;
            a=i;
        }
        else extand[i]=L;
    }
    return 0;
}
int main()
{
    int T,i,j,d=1,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%s",str1);
        int len=strlen(str1);
        strcpy(str2,str1);
        strcat(str1,str2);
        kmpnext(str2,len);
        int t=len-knext[len];
        k=1;
        if(len%t==0) k=len/t;
        EKMP(str1,str2);
        int Min=0,Max=0,equal=0;
        for(i=0;i<len;i++)
        {
            if(extand[i]>=len) equal++;
            else
            {
                if(str1[i+extand[i]]>str1[extand[i]]) Max++;
                else Min++;
            }
        }
        printf("Case %d: %d %d %d\n",d++,Min/k,equal/k,Max/k);
    }
    return 0;
}
时间: 2024-12-25 09:55:41

hdu 4333 不错的EKMP+KMP的相关文章

HDU 4333 Revolving Digits 扩展KMP

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4333 题意:给以数字字符串,移动最后若干位到最前边,统计得到的数字有多少比原来大,有多少和原来相同,有多少比原来的小. 思路:拓展KMP中的next数组标记的是子串和母串的公共前缀的长度,要将字符串长度变成原来二倍,这样如果变换后不是完全相同的数字也即公共前缀长度大于等于字符串长度,那么字母串公共前缀的下一位的大小比较就是题目所要求的比较.由于相同的数字串只算一次,则只要统计比较第一个"循环节"

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

题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数. SAM乱搞失败 当然要先变SS了 然后考虑每个后缀前长为n个字符,把它跟S比较就行了 如果用后缀家族的话复杂度要加上log,本题会TLE吧 求一个串S的每个后缀与另一个串T的最长公共前缀可以用扩展KMP!复杂度O(n+m) 看课件吧 从1开始写真不容易以后再也不从1开始了,判断位置好麻烦好容易错 next[i]=LCP(T[i,m],T) extend[i]=LCP(S[i,n],T)

扩展KMP,附上例题(HDU - 4333 Revolving Digits)

给出模板串S和串T,长度分别为Slen和Tlen,在线性时间内,对于每个S[i](0<=i<Slen),求出S[i..Slen-1]与T的 最长公共前缀长度,记为extend[i],extend[i]存放s[i]开始与T的最长公共前缀长度. 例子 a a a a a a a b b b a a a a a c extend 5 4 3 2 1 0 0 0 0 0 HDU - 4333 Revolving Digits Time Limit: 3000/1000 MS (Java/Others)

hdu 4300 Clairewd’s message (KMP)

给定一个翻译表,即第i个字母用哪个字母表示 再给一个串,里面前面为密文,后面为明文,密文一定是完整的,但明文不完整或可能没有 求这个完整的前面密文后面明文的串 # include <stdio.h> # include <algorithm> # include <string.h> using namespace std; int len; int next[100010]; char a1[100010],a2[100010],a3[100010]; void Ge

hdu 4089 不错的DP 北京现场赛题

http://acm.hdu.edu.cn/showproblem.php?pid=4089 还有疑惑,需要重新推: 但是学到的: 1.A=a+b+c  abc是三种情况,那么P(A)=a*P(a->事件)+b*P(b->事件)+c*P(c->事件); a->事件意思是 在a情况下的事件,就是全概率公式的思想吧 2.一定注意每一步会不会出现分母为0 的情况,以及预处理的时候对于一些特殊情况导致自己的式子会出现分母为0的排除掉 3.概率DP经常出现推出了式子但是自己不会写代码的情况,

HDU 2594 Simpsons’ Hidden Talents KMP题解

KMP的应用.直接使用s1产生next 数组,然后在s2中搜索s1,那么记录最后一个搜索到的数值,就是s1的前缀在s2中的最长后缀了. 本题应该不能直接调用strstr了吧. #include <stdio.h> #include <vector> #include <string.h> #include <algorithm> #include <iostream> #include <string> #include <li

hdu 3374 String Problem (kmp+最大最小表示法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题目大意:输出最大和最小的是从哪一位开始的,同时输出最小循环节的个数. 这里简单介绍对字符串最小表示的方法: (1)  利用两个指针p1, p2.初始化时p1指向s[0], p2指向s[1]. (2)  k = 0开始,检验s[p1+k] 与 s[p2+k] 对应的字符是否相等,如果相等则k++,一直下去,直到找到第一个不同,(若k试了一个字符串的长度也没找到不同,则那个位置就是最小表示位置,

HDU 2087 剪花布条 KMP题解

KMP的应用,不过查找的时候注意一点就够了:查找到一个子串的时候,直接跳过整个串,而不是使用next数组前跳,因为根据题意需要剪出小饰条,小饰条之间不能重叠. const int MAX_N = 1001; char txt[MAX_N], pat[MAX_N]; int next[MAX_N], len; void genNext() { for (int i = 1, j = 0; i < len; ) { if (pat[i] == pat[j]) next[i++] = ++j; els

扩展KMP - HDU 4333 Revolving Digits

Revolving Digits Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=4333 Mean: 给你一个字符串,你可以将该字符串的任意长度后缀截取下来然后接到最前面,让你统计所有新串中有多少种字典序小于.等于.大于原串. analyse: KMP的经典题. 首先我们将原串扩展成两倍,算一遍扩展KMP(自匹配),时间复杂度O(n). 这样一来,我们就得到了eKMP[i],eKMP[i]代表s[i...len-1]与s的最长