2016 Multi-University Training Contest 4 1001 Another Meaning

KMP算法详解与应用
本文详细介绍KMP算法原理及其实现方式,并通过一个具体的字符串匹配问题实例展示了如何使用KMP算法来解决实际问题。文章提供了完整的代码实现,并解释了算法背后的逻辑。

题目链接:点击打开链接

题目大意:给你一个字符串和一个有两个意思的字符串,问前一个字符串能有多少种不同的意思。

解题思路:用kmp找重复,再用dp计算数量方程也很简单dp[i]=dp[i-1]+dp[i-len2](如果i是匹配的最后一个位置)

代码:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include "cstdio"
#include "string"
#include "string.h"
#include "map"
#include "bitset"
using namespace std;
const int mod = 1000000007;
char str1[100001], str2[100001];
int vis[100001], dp[100001];
void GetFail(char *P, int *f)
{
    int m = strlen(P);
    f[0] = 0;
    f[1] = 0;
    for (int i = 1; i < m; i++)
    {
        int j = f[i];
        while (j && P[i] != P[j]) j = f[j];
        f[i + 1] = (P[i] == P[j] ? j + 1 : 0);
    }
}
int Find(char *T, char *P, int *f)
{
    int n = strlen(T), m = strlen(P);
    GetFail(P, f);
    int j = 0;
    for (int i = 0; i < n; i++)
    {
        while (j && P[j] != T[i]) j = f[j];
        if (P[j] == T[i]) j++;
        if (j == m) vis[i + 1] = 1;
    }
    return -1;
}
int f[100001];
int main()
{
    int T, cas = 0;
    scanf("%d", &T);
    while (T--)
    {
        memset(vis, 0, sizeof(vis));
        scanf(" %s %s", str1+1, str2+1);
        int len1 = strlen(str1+1), len2 = strlen(str2+1);
        printf("Case #%d: ", ++cas);
        Find(str1 + 1, str2 + 1, f);
        long long ans = 0;
        dp[0] = 1; 
        for (int i = 1;i <= len1;i++)
        {
            if (vis[i])
                dp[i] = (dp[i - len2] + dp[i - 1]) % mod;
            else
                dp[i] = dp[i - 1];
        }
        printf("%lld\n", dp[len1]);
    }
    return 0;
}




kmp模版:

#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<ctime>
#include "cstdio"
#include "string"
#include "string.h"
#include "map"
#include "bitset"
using namespace std;
const int mod = 1000000007;
const int MAXN = 100001;
struct Kmp
{
	char str1[MAXN], str2[MAXN];
	int vis_end[MAXN], vis_start[MAXN];//vis_end
	int dp[MAXN];
	int len1, len2;
	void init()
	{
		memset(vis_end, 0, sizeof(vis_end));
		memset(vis_start, 0, sizeof(vis_start));
		scanf(" %s %s", str1 + 1, str2 + 1);
		len1 = strlen(str1 + 1), len2 = strlen(str2 + 1);
	}
	void GetFail(char *P, int *f)
	{
		int m = strlen(P);
		f[0] = 0;
		f[1] = 0;
		for (int i = 1; i < m; i++)
		{
			int j = f[i];
			while (j && P[i] != P[j]) j = f[j];
			f[i + 1] = (P[i] == P[j] ? j + 1 : 0);
		}
	}
	int Find(char *T, char *P, int *f)
	{
		int n = strlen(T), m = strlen(P);
		GetFail(P, f);
		int j = 0;
		for (int i = 0; i < n; i++)
		{
			while (j && P[j] != T[i]) j = f[j];
			if (P[j] == T[i]) j++;
			if (j == m)
			{
				vis_end[i + 1] = 1;
				vis_start[i + 1 - m] = 1;
			}
		}
		return -1;
	}
}kmp;
int f[100001];
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		kmp.init();
		kmp.Find(kmp.str1 + 1, kmp.str2 + 1, f);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值