[机房练习赛4.7] 深意 KMP

深意(meaning.in/meaning.out)

有的词语常常别有深意,比如hehe可以单纯的表示hehe,也可以表示“excuse me?!”,现给出一段话s,和一个单词t,已知单词t有别有深意,也就是说有两个意思,求s可能有多少个意思?答案对1000000007取模。
【输入格式】
第一行一个数n,表示测试的组数。
接下来n组,每组两行,表示s和t。
【输出格式】
一共n行,第i行表示第i组的s个意思个数。
5
【输入样例】
4
hehehe
hehe
woquxizaolehehe
woquxizaole
hehehehe
hehe
woyaoqugenbierenliaotianle
wanan
【输出样例】
3
2
5
1
【样例解释】
黑色表示取原意,红色表示取深意。
第1组: hehehe, hehehe, hehehe
第3组: hehehehe, hehehehe, hehehehe, hehehehe, hehehehe
【数据规模】
50% 数据满足 len(s),len(t) ≤ 1000。
100% 数据满足len(t) ≤ len(s) ≤ 100000, n ≤ 10。
s和t仅包含小写字母。
【解法】
KMP+DP
设dp[i]为s长度为i的前缀,有多少种意思,初始情况dp[0]=1。
一般情况下dp[i] = dp[i-1]
如果在s中找到一个t,则t会为s带来新的意思,即是说dp[i] = dp[i-1] + dp[I – lent]。最后输出dp[lens]即可。
如果暴力找出所有t,应该可以得到50分。
我们使用KMP算法快速找到所有s中的t,就可以通过本题。

#include
#include
#include
using namespace std;
const int mod = 1000000000 + 7;
const int N = 100000 + 5;
int T;
char s[N],t[N];
int next[N],dp[N];
void getgo(){
    int i = 0,j = -1;
    int len = strlen(t);
    next[0] = -1;
    while( i < len ){
        if( j == -1 || t[i] == t[j] ){
            i++;j++;
            next[i] = j;
        } else j = next[j];
    }
}
void calculate(){
    int i = 0,j = 0;
    int len1 = strlen(s); int len2 = strlen(t);
    while( i < len1 ){
        if( j == -1 || s[i] == t[j] ){
            i++;j++;
            dp[i] = dp[i-1];
            if( j == len2 ){
                dp[i] = (dp[i] + dp[i-j]) % mod;
                j = next[j];
            }
        } else j = next[j];
    }
}
int main(){
    freopen("meaning.in","r",stdin);
    freopen("meaning.out","w",stdout);
    scanf("%d", &T);
    while(T--){
        scanf("%s", s);scanf("%s", t);
        getgo();
        dp[0] = 1;
        calculate();
        int len = strlen(s);
        printf("%d\n",dp[len]);
    }
    return 0;
}

你可能感兴趣的:(KMP,机房练习赛)