您的位置:首页 > 其它

hdu 5763 Another Menning(KMP && DP)

2016-08-05 21:20 211 查看
Another Meaning


Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 1231 Accepted Submission(s): 577

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”.

Author

FZU

Source

2016 Multi-University Training Contest 4

多校上的一道题,当时一直没有读懂题。比赛完,看了看样例,才发祥是道字符串匹配的题。

KMP算法

说到 字符串匹配的话,就一定绕不开的三个人是:Knuth,Morris,Pratt。对滴,他们就是KMP算法的创始人。


这种算法不太容易理解,网上有很多解释,但读起来都很费劲。这里我说一下,一些自己的看法。

KMP算法的精髓之处,也是最难懂的地方在于 next数组。当模式串与原串失配(不匹配)的时候,他是用来跳转的,很大程度上减少了匹配的次数。先上一下,代码:

void make_next(const p[], next[]){
int q, k; //q:模版字符串下标;k:最大前后缀长度
int m = strlen(p); //模板字符串的长度
next[0] = 0;
for(q = 1, k = 0; q < m; q++){
while(k > 0 && p[q] != p[k])
k = next[k-1];
if(p[q] == p[k])
k++;
next[q] = k;
}
}


这里着重说一下,for循环里面的工作:

这是一个一般化的过程,正在计算的next[k], next[1],,,,next[k-1]是已知的。

此时,正在匹配p[q] , p[k];

如果相等呢,直接跳出循环,将k值赋值给next[q];

关键是不相等呢,P[k]已经和P[q]失配了,而且P[q-k] ··· P[q-1]又与P[0] ···P[k-1]相同,看来P[0]···P[k-1]这么长的子串是用不了了,那么我要找个同样也是P[0]打头、P[k-1]结尾的子串即P[0]···P[j-1] (j==next[k-1]),看看它的下一项P[j]是否能和P[q]匹配。这有点递归的意思,体会一下吧。

好啦,有了KMP之后,问题就转换为区间的覆盖问题。这是因为,我们可以通过KMP找到所以匹配开始的点。

简单的DP

状态转移方程为:

dp[i] = dp[i+1] + dp[j] (j 是 不与区间 i 覆盖的第一个区间);

注意:有事没事就要取模,否则会爆long long;

上AC代码:

#include <map>
#include <set>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <string>
#include <bitset>
#include <cstdio>
#include <limits>
#include <vector>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <numeric>
#include <sstream>
#include <iostream>
#include <algorithm>
#define MEM(a,x) memset(a,x,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 100000 + 100;
int t[maxn], next1[100000 + 100];
ll dp[maxn];
void Init(int n)
{
for(int i = 0;  i < n; i++)
{
t[i] = next1[i] = dp[i] = 0;
}
}
void makenext1(const char P[],int next1[])
{
int q,k;
int m = strlen(P);
next1[0] = 0;
for (q = 1,k = 0; q < m; ++q)
{
while(k > 0 && P[q] != P[k])
k = next1[k-1];
if (P[q] == P[k])
{
k++;
}
next1[q] = k;
}
}

int kmp(const char T[],const char P[],int next1[], int t[])
{
int n,m, kase = 0;
int i,q;
n = strlen(T);
m = strlen(P);
makenext1(P,next1);
for (i = 0,q = 0; i < n; ++i)
{
while(q > 0 && P[q] != T[i])
q = next1[q-1];
if (P[q] == T[i])
{
q++;
}
if (q == m)
{
t[kase++] = i - m + 1;
//printf("Pattern occurs with shift:%d\n",(i-m+1));
}
}
return kase;
}
int main()
{
//    freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n, q = 0;
cin >> n;
char T[maxn], P[maxn];
while(n--)
{
cin >> T >> P;
int n1 = strlen(T);
int n2 = strlen(P);
Init
b286
(max(n1, n2) + 1);
int len = kmp(T,P,next1, t);
dp[t[len-1]] = 2;
if(len <= 1)
{
cout <<"Case #"<< ++q <<": ";
cout << len+1 << endl;
continue;
}
for(int i = len-2; i >= 0; i--)
{
dp[t[i]] += dp[t[i+1]]%1000000007;
int k = i+1;
int f = 0;
while(t[i] + n2 > t[k] && k < len)
{
k++;
if(k == len) f = 1;
}
if(!f) dp[t[i]] += dp[t[k]]%1000000007;
else dp[t[i]] += 1;
}
cout <<"Case #"<< ++q <<": ";
cout << dp[t[0]]%1000000007<< endl;
//printf("time=%.3lf\n",(double)clock()/CLOCKS_PER_SEC);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  KMP acm dp