HDU 5763 Another Meaning dp+kmp优化

本文介绍了一种基于KMP算法优化的字符串匹配问题解决方案,通过预处理模式串来提高匹配效率,并利用动态规划方法计算不同匹配状态的数量。文章提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击打开链接

给你一个主串一个子串,然后主串中匹配到子串就可以把当前部分改为*,

问主串有多少中不同的样子。

纯dp做法。

统计种类数的话,

dp[i]={    如果后缀串不完全匹配的话:dp[i]  =  dp[j-1];

      如果后缀串完全匹配的话 dp[i] =  dp[i - 1] + dp[i-len2];

         }

#include<iostream>
#include<cstring>
#include<map>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<stack>
#define mod 19999
#define INF 0x3f3f3f3f
#define bug  puts("***********")
using namespace std;
long long dp[1000000];
char s1[1000000],s2[1000000];
bool judge(int index,int len){
    if(index+1<len) return 0;
    for(int i=0;i<len;i++){
        if(s1[index-i]!=s2[len-i-1]){
            return 0;
        }
    }
    return 1;
}
int main(){
    int t,n,len;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%s%s",s1,s2);
        int len1=strlen(s1);
        int len2=strlen(s2);
        int sum=0;
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        for(int i=0;i<len1;i++){
            dp[i+1]=dp[i];
            if(judge(i,len2)){
                dp[i+1]=(dp[i+1]+dp[i+1-len2])%1000000007;
            }
        }
        printf("Case #%d: %d\n",cas,dp[len1]);
    }
    return 0;
}

用kmp优化的话只需要用kmp提前将每个匹配串的 最后一位的下标存入数组中去,这样就省去了dp中的每次的从头到尾的匹配了。


#include <bits/stdc++.h>  

using namespace std;  
#define REP(i,k,n) for(int i=k;i<n;i++)  
#define REPP(i,k,n) for(int i=k;i<=n;i++)  
#define scan(d) scanf("%d",&d)  
#define scann(n,m) scanf("%d%d",&n,&m)  
#define mst(a,k)  memset(a,k,sizeof(a));  
#define LL long long  
#define N 100005  
#define mod 1000000007  
char a[1000000],b[1000000];  
LL dp[100005];  
  
int Next[N],idx[N];  
void MakeNext(int m)  
{  
    Next[0]=-1;  
    int i=0,j=-1;  
    while(i<m)  
    {  
        if(j==-1||b[i]==b[j])  
        {  
            ++i,++j;  
            Next[i]=j;  
        }  
        else j=Next[j];  
    }  
}  
int KMP(int n,int m)  //a是主串,b是模式串,n是主串长,m是模式串长  
{  
    MakeNext(m);  
    int i=0,j=0,ret=0;  
    while(i<n)  
    {  
        if(a[i]==b[j]||j==-1)++i,++j;  
        else j=Next[j];  
        if(j==m)  
        {  
            idx[i] = 1; //各匹配到的模式串在主串中的首字母位置  
            j=Next[j];  //允许在主串中重叠查找  
            /*j=0;  //不允许重叠*/  
        }  
    }  
    return ret; //成功匹配次数  
}  
int main()  
{  
    //freopen("in.txt","r",stdin);  
    //freopen("out.txt","w",stdout);  
    int t;  
    scan(t);  
    for(int cas=1;cas<=t;cas++)  
    {  
<span style="white-space:pre">	</span>memset(idx,0,sizeof(idx));
        scanf("%s%s",a,b);
        int len = strlen(a);  
        int len2 = strlen(b);  
        dp[0]=1;  
        for(int i=1;i<=len;i++)  
        {  
            dp[i] = dp[i-1];  
            if(i>=len2 && idx[i-1]+idx[i-len2-1]==2))  
                dp[i] = ( dp[i] + dp[i-len2] ) % mod;  
  
        }  
        printf("Case #%d: %I64d\n",cas,dp[len]);  
    }  
  
  
    return 0;  
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值