hdu 4333 扩展kmp+kmp重复字串去重

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

关于kmp next数组求最短重复字串问题请看;http://www.cnblogs.com/z1141000271/p/7406198.html

扩展kmp请看:http://www.cnblogs.com/z1141000271/p/7404717.html

题目大意:一个数字,依次将第一位放到最后一位,问小于本身的数的个数及等于本身的个数和大于本身的个数,但是要注意重复的不再计算

题解:我们把得到的串double一下(比如s=aa double之后 s=aaaa),然后对double之后得到的串做一个次扩展kmp,然后便利得到的Next数组。如果公共前缀匹配>=原串长度则e++,对于公共前缀小于原串长度的,我们去比较失配的第一位就可以了。再就是去重的问题,这个要注意!如果原串可以由更小的串重复得到,那我们计算的结果就有很多重复的。

(注意double 以及去重两个操作的使用)

ac代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#define mt(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int extend[200001];
int Next[200001];
int min(int x,int y)
{
    if(x>y) return y;
    return x;
}
int knext[200005];
void getknext(char s[],int len)
{
    mt(knext);
    int i=0;
    int j=-1;
    knext[i]=j;
    while(i<len)
    {
        if(j==-1 || s[i]==s[j]) knext[++i]=++j;
        else j=knext[j];
    }
}
void getNext(char t[],int len)
{
    mt(Next);
    //ll len=strlen(t);
    Next[0]=len;
    int a,p;
    a=1;
    while( a<len && t[a]==t[a-1]) a++; // 求出长度为1的时候 解为多少
    Next[1]=a-1;
    a=1;
    for(int i=2;i<len;i++) // 后续的按照算法来就好
    {
        p=a+Next[a]-1;
        if((i-1)+Next[i-a] < p ) Next[i]=Next[i-a];// 第一种情况 没有超过等于的部分
        else // 超过的话就不好直接用next的定义 需要后续的遍历
        {
            ll j = (p - i + 1) > 0 ? (p - i + 1) : 0;
            while(i + j < len && t[i+j] == t[j]) j++;
            Next[i]=j;
            a=i;
        }
    }
}
char s[2000005];// s->exkmp t->Next
int main()
{
    int Case;
    scanf("%d",&Case);
    for(int z=1;z<=Case;z++)
    {
        scanf("%s",s);
        int len=strlen(s);
        int j=0;
        int l,e,g;
        getknext(s,len);
        int temp=len-knext[len]; // 最小重复长度
        if(len%temp) temp=1;
        else temp=len/temp;

        for(int i=0;i<len;i++)
        {
            s[len+i]=s[i];
        }
        getNext(s,2*len);
        l=e=g=0;
        for(int i=0;i<len;i++)
        {
            if(Next[i]>=len) e++;
            else
            {
                int temp=i+Next[i];// postion of not match
                if(s[temp]<s[Next[i]]) l++;
                else if(s[temp]>s[Next[i]])g++;
            }
        }
        printf("Case %d: %d %d %d\n",z,l/temp,e/temp,g/temp);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/z1141000271/p/7406348.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值