hdu5775 Another Meaning(扩展kmp+dp)

 

1003:hint有修改,已加粗。请各位选手注意。More...

Another Meaning

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1508    Accepted Submission(s): 382

 

Problem Description

As is known to all, in many cases, a word has two meanings. Such as “hehe”, which not only means “hehe”, but also means “excuse me”. 
Today, ?? is chating with MeiZi online, MeiZi sends a sentence A to ??. ?? is so smart that he knows the word B in the sentence has two meanings. He wants to know how many kinds of meanings MeiZi can express.

 

 

Input

The first line of the input gives the number of test cases T; T test cases follow.
Each test case contains two strings A and B, A means the sentence MeiZi sends to ??, B means the word B which has two menaings. string only contains lowercase letters.

Limits
T <= 30
|A| <= 100000
|B| <= |A|
 

 

 

Output

For each test case, output one line containing “Case #x: y” (without quotes) , where x is the test case number (starting from 1) and y is the number of the different meaning of this sentence may be. Since this number may be quite large, you should output the answer modulo 1000000007.

 

 

Sample Input

 

4 hehehe hehe woquxizaolehehe woquxizaole hehehehe hehe owoadiuhzgneninougur iehiehieh

 

 

Sample Output

 

Case #1: 3 Case #2: 2 Case #3: 5 Case #4: 1

Hint

In the first case, “ hehehe” can have 3 meaings: “*he”, “he*”, “hehehe”. In the third case, “hehehehe” can have 5 meaings: “*hehe”, “he*he”, “hehe*”, “**”, “hehehehe”.

 

 

 

【题意】给你两个字符串,用b串匹配a串,在两个串完全匹配的位置,可以通过变换变成一个*,a串上可以多个位置都变换,问最后a串有多少种形式。 

 

【分析】我们可以通过扩展kmp,extend[i]:y[i..n-1]与x[0...m-1]的最长公共前缀,判断是否完全匹配。

然后dp,状态表示: dp[i]代表以i为结尾的a串有多少表现形式。

状态转移: (1)当以i为结尾的a的字串与b完全匹配时,dp[i]=dp[i]-lenb+dp[i-1];

(2) 没有完全匹配时,dp[i]=dp[i-1];

 

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<vector>

#define F first
#define S second
#define mp make_pair
using namespace std;
const int maxn = 1e5+10;
const int mod = 1000000007;
char a[maxn];
char b[maxn];
int nextt[maxn];
int extend[maxn];
int dp[maxn];
void pre_EKMP(char x[],int m,int next[])
{
    next[0]=m;
    int j=0;
    while(j+1<m && x[j]==x[j+1]) j++;
    next[1]=j;
    int k=1;
    for(int i=2; i<m; i++)
    {
        int p=next[k]+k-1;
        int L=next[i-k];
        if(i+L<p+1) next[i]=L;
        else
        {
            j=max(0,p-i+1);
            while(i+j<m && x[i+j]==x[j])j++;
            next[i]=j;
            k=i;
        }
    }
}
void EKMP(char x[],int m,char y[],int n,int next[],int extend[])
{
    pre_EKMP(x,m,next);
    int j=0;
    while(j<n && j<m && x[j]==y[j])j++;
    extend[0]=j;
    int k=0;
    for(int i=1; i<n; i++)
    {
        int p=extend[k]+k-1;
        int L=next[i-k];
        if(i+L<p+1) extend[i]=L;
        else
        {
            j=max(0,p-i+1);
            while(i+j<n && j<m &&   y[i+j]==x[j])j++;
            extend[i]=j;
            k=i;
        }
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    int u=1;
    while(T--)
    {
        scanf("%s",a);
        scanf("%s",b);
        EKMP(b,strlen(b),a,strlen(a),nextt,extend);
        int lena=strlen(a);
        int lenb=strlen(b);
        memset(dp,0,sizeof(dp));
        for(int i=0; i<lenb-1; i++) dp[i]=1;
        for(int i=lenb-1; i<lena; i++)
        {
            if(extend[i-lenb+1]==lenb)
            {
                if(i-lenb<0) dp[i]++;
                else
                    dp[i]+=dp[i-lenb];
                dp[i]%=mod;
                if(i-1<0) dp[i]++;
                else
                    dp[i]+=dp[i-1];
                dp[i]%=mod;
            }
            else
            {
                dp[i]+=dp[i-1];
                dp[i]%=mod;
            }
        }

        printf("Case #%d: %d\n",u++,dp[lena-1]);
    }
    return 0;
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值