ZOJ 3587 Marlon's String 扩展KMP

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3587

题意:给出两个字符串S和T,S,T<=100000.拿出S的两个子串(可以重叠),将两个子串连接起来成为字符串T的方法有多少种。

思路:用扩展KMP求出S的从每位开始的子串与T的公共前缀,再将两个子串翻转,再用扩展KMP求出S反的从每位开始的子串与T反的公共前缀。找出其中和为T子串长度的S公共前缀和S反的公共前缀的数量,相乘为结果。

代码:

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <ctype.h>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define eps 1e-8
#define INF 0x7fffffff
#define maxn 10005
#define PI acos(-1.0)
#define seed 31//131,1313
typedef long long LL;
typedef unsigned long long ULL;
using namespace std;
const int N = 101010;
int next_a[N],extand_a[N],next_c[N],extand_c[N];
void getnext(char *T,int *next,int *extand) // next[i]: 以第i位置开始的子串 与 T的公共前缀
{
    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++;// 枚举(p+1,length) 与(p-k+1,length) 区间比较
            next[k] = j, a = k;
        }
        else next[k] = L;
    }
}
void getextand(char *S,char *T,int *next,int *extand) //s是母串,t是模式串
{
    memset(next,0,sizeof(next));
    getnext(T,next,extand);
    int Slen = strlen(S), Tlen = strlen(T), a = 0;
    int MinLen = Slen>Tlen?Tlen:Slen;
    while(a<MinLen && S[a]==T[a]) a++;
    extand[0] = a, a = 0;
    for(int k = 1; k < Slen; k++)
    {
        int p = a+extand[a]-1, L = next[k-a];
        if( (k-1)+L >= p )
        {
            int j = (p-k+1)>0? (p-k+1) : 0;
            while(k+j<Slen && j<Tlen && S[k+j]==T[j] ) j++;
            extand[k] = j;
            a = k;
        }
        else extand[k] = L;
    }
}
char a[100005],b[100005],c[100005],d[100005];
LL t_a[100005],t_c[100005];
void init()
{
    memset(t_a,0,sizeof(t_a));
    memset(t_c,0,sizeof(t_c));
}
int main()
{
    //freopen("1.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%s",a);
        scanf("%s",b);
        int len_a=strlen(a);
        for(int i=0;i<len_a;i++)
            c[i]=a[len_a-1-i];
        c[len_a]='\0';
        int len_b=strlen(b);
        for(int i=0;i<len_b;i++)
            d[i]=b[len_b-1-i];
        d[len_b]='\0';
        getextand(a,b,next_a,extand_a);
        getextand(c,d,next_c,extand_c);
        for(int i=0;i<len_a;i++)
        {
            t_a[extand_a[i]]++;
            t_c[extand_c[i]]++;
        }
        for(int i=len_a-1;i>=1;i--)
        {
            t_a[i]+=t_a[i+1];
            t_c[i]+=t_c[i+1];
        }
        LL ans=0;
        for(int i=1;i<len_b;i++)
        {
            ans+=t_a[i]*t_c[len_b-i];
        }
        printf("%lld\n",ans);
    }
    return 0;
}

ZOJ 3587 Marlon's String 扩展KMP

时间: 2024-12-07 07:12:46

ZOJ 3587 Marlon's String 扩展KMP的相关文章

acdream1116 Gao the string!(扩展KMP)

今天是字符串填坑的一天,首先填的第一个坑是扩展KMP.总结一下KMP和扩展KMP的区别. 在这里s是主串,t是模式串. KMP可以求出的是以s[i]为结尾的串和 t前缀匹配的最长的长度.假如这个长度是L的话,则: s[i-L+1...i]=t[0...L] 而所谓的失配指针f[i]指的就是当前i点失配时要匹配的长度,实际是用t文本串去匹配t. 扩展KMP则是以s[i]为起始的串和 t前缀匹配的最长的长度. 假如这个长度的话,则: s[i..i+L-1]=t[0...L] 扩展KMP里的nxt数组

HDU - 3336 Count the string (扩展kmp)

It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example: s: "abab" The prefixes are: "a", "ab&qu

xtu字符串 C. Marlon&#39;s String

C. Marlon's String Time Limit: 2000ms Memory Limit: 65536KB 64-bit integer IO format: %lld      Java class name: Main Long long ago, there was a coder named Marlon. One day he picked two string on the street. A problem suddenly crash his brain... Let

hdu2328 Corporate Identity 扩展KMP

Beside other services, ACM helps companies to clearly state their "corporate identity", which includes company logo but also other signs, like trademarks. One of such companies is Internet Building Masters (IBM), which has recently asked ACM for

扩展KMP算法

扩展KMP,用于求s的后缀的最长前缀.用extand数组表示第i个后缀的最长前缀的字符个数. 注意几点:1.next数组是对T的   2.extand数组是对S的 3.应用:回文,重复串等 代码如下: 1 #include<iostream> 2 #include<string> 3 #include<cstdio> 4 using namespace std; 5 const int MM=100005; //长度最大值 6 int next[MM],extand[M

扩展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的最长

HDU 4300 (扩展KMP或KMP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4300 题意:说实话,看半天题目,愣是没看懂,百度题意才看懂,大概意思就是:第一个串串为匹配串,第i个代表字母顺序中的第i个,比如第一个是q,那么,q就代表a. 第二个串是密文+明文,密文全部都有,但明文可能不全,输出完整的密文+明文. 题解:有两种做法,第一种,用扩展KMP: 1.先把s2砍半,前面一半必定为密文,后面一半可能是密文+明文. 2.把前面的一半转化成明文. 3.用后面的和前面的找最长公

浅谈Manacher算法与扩展KMP之间的联系

首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解,网上解法颇多,时间复杂度也不尽相同,这里列述几种常见的解法. 解法一 通过枚举S的子串,然后判断该子串是否为回文,由于S的子串个数大约为,加上每次判断需要的时间,所以总的时间复杂度为,空间复杂度为. bool check(string &S, int left, int right) { while (left < right && S[left]

HDU 6153 A Secret(扩展KMP模板题)

A Secret Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Total Submission(s): 2523    Accepted Submission(s): 934 Problem Description Today is the birthday of SF,so VS gives two strings S1,S2 to SF as a present,w