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;
}
时间: 2024-10-22 23:39:33

hdu 4333 扩展kmp+kmp重复字串去重的相关文章

网上有些例子有问题,所以重新写了下 求字符串的最长不重复字串

假设有一个字符串"abcdebfgh" 那么最长不重复字串是"cdebfgh",长度是7 若是:abcdbefbghijij 应输出:befbghij 以abcbef这个串为例 用一个数据结构pos记录每个元素曾出现的下标,初始为-1 从s[0]开始,pos['a'] == -1,说明a还未出现过,令pos['a'] = 0,视为将a"加入当前串",同时长度++ 同理令pos['b'] = 1,pos['c'] = 2 到s[3]时,pos['b

HDU 4333 扩展KMP

点击打开链接 题意:一个数字,依次将第一位放到最后一位,问小于本身的数的个数及等于本身的个数和大于本身的个数,但是要注意重复的不再计算 思路:用扩展KMP我们可以处理,先将串复制到后面一次,然后求扩展KMP,那么我们如何比较呢,如果extand[i]的值大于串的长度len,说明我以i为开头的串和原串的匹配大于len,也就说明这个串和原串相等,接下来就是另外两种情况,若extand[i]匹配到了第三位,那么久比较原串的第三位和以i开始的第三位即可,比较过后,处理重复的串,用KMP即可处理,如果串是

POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题

POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 后缀数组写法放在后面那一题,SPOJ - REPEATS是求子串类型,KMP就不好处理了 这里放下处理KMP的AC代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <c

poj 2406 求最短重复字串

题解: KMP中next数组的巧妙运用.在这里我们假设这个字符串的长度是len,那么如果len可以被len-next[len]整除的话,我们就可以说len-next[len]就是那个最短子串的长度为什么呢? 假设我们有一个字符串ababab,那么next[6]=4对吧,由于next的性质是,匹配失败后,下一个能继续进行匹配的位置,也就是说,把字符串的前四个字母,abab,平移2个单位,这个abab一定与原串的abab重合(否则就不满足失败函数的性质),这说明了什么呢,由于字符串进行了整体平移,而

找出字符串的最长不重复字串

这是我遇到的一道校招题目: 给定一字符串只包含数字,请写一个算法,找出该字符串中的最长不重复子串(不重复是指子串中每一元素不同于子串中其他元素) 如: "120135435"最长不重复子串为 "201354" 要求用java或者c来写,我用了java. /** * 思想: *      从头开始截取字符串,只要后一个元素不在截取的字符串里,就更新截取,多截取一个元素. *       如果发现后一个元素出现在字符串里, 将最后截取的字符串存为临时结果,开始位置后移一

POJ 3415 Common Substrings(后缀数组求重复字串)

题目大意:给你两个字符串,让你求出来两个字符串之间的重复子串长度大于k的有多少个. 解题思路: 先说论文上给的解释:基本思路是计算A的所有后缀和B的所有后缀之间的最长公共前缀的长度,把最长公共前缀长度不小于k的部分全部加起来.先将两个字符串连起来,中间用一个没有出现过的字符隔开.按height值分组后,接下来的工作便是快速的统计每组中后缀之间的最长公共前缀之和.扫描一遍,每遇到一个B的后缀就统计与前面的A的后缀能产生多少个长度不小于k的公共子串,这里A的后缀需要用一个单调的栈来高效的维护.然后对

最长无重复字串

给定一个字符串,找出不含有重复字符的最长子串的长度. 示例: 给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3. 给定 "bbbbb" ,最长的子串就是 "b" ,长度是1. 给定 "pwwkew" ,最长子串是 "wke" ,长度是3.请注意答案必须是一个子串,"pwke" 是 子序列  而不是子串. class Solution

LeetCode系列字符串操作(一)ZigZag输出,寻找最大不重复字串长度。

ZigZag Conversion The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility) P A H N A P L S I I G Y I R And then read line by line

[leetcode]3无重复字符的最长字串

本题思路较清楚,通过一个数组记录各个位置所能够引导的最长字符串的长度即可. 稍微有一点难度在于如何向前寻找时判断已经出现了重复字符串,我采用的思路为只有当前项的长度等于当前长度时,认为尚未出现重复字符串,并更新前项长度++. 1 int max=0; 2 int st[100000]={0};//表示以它为开头的最长不重复字串长度 3 int i=0; 4 char p; 5 while(s[i]!='\0') 6 { 7 p=s[i]; 8 st[i]=1; 9 max=st[i]; 10 f