Codeforces 808G - Anthem of Berland KMP and简单DP

题意:给两个字符串s,t   s的一些位置的字母任意,问t最多在s上出现几次 (可重叠)

解:

****滚动数组容易忘清空。**

1.上来想到AC自动机,-->只有一个t  -->kmp求失配指针。

然后转移就是:

dp[i+1][jnxt]=max(dp[i+1][jnxt],dp[i][j]+(jnxt==lent));

其中第一维长度,第二维是当前长度匹配t的长度多少

2.一直卡在第36点,然后看了别人的代码 。发现比我多一个特判 lent>lens时直接输出0。本人注释掉这个特判,别人的也T了。

分析:把这个特判放在 kmp求失配指针的后边也T了。我不知道求失配指针的复杂度。。。

 

#include<bits/stdc++.h>
#define en '\n'
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn = 1e5+5;
int rd(){int tem;scanf("%d",&tem);return tem;}
int n,k;
int nxt[maxn];
char s[maxn],t[maxn];
int dp[2][maxn];
int ed[maxn][27];
void kmp(){
    //#define int register int
    int j=-1,i=0;nxt[0]=-1;int len=strlen(t);
    while(i<len){
        if(j==-1 or t[i]==t[j]){
            i+=1,j+=1,nxt[i]=j;
        }else j=nxt[j];
    }
    for(int i=0;i<=len;++i){
        for(int j=0;j<26;++j){
            char tem='a'+j;
            int  tt=i;
            while(tem!=t[tt] and tt!=-1)tt=nxt[tt];
            tt+=1;
            ed[i][j]=tt;
        }
    }
}
inline int Max(int a,int b){
if(a>b)return a;return b;
}
signed main(){
    #ifdef local
    freopen("input2.txt","r",stdin);
    #endif
    #define int register int
    scanf("%s",s+1);scanf("%s",t);
    int len=strlen(s+1);
    int lent=strlen(t);
    if(lent>len){
        cout<<0<<en;return 0;
    }
    kmp();
    dp[0][0]=1;int ans=1;
    for(int i=0;i<len;++i){
        bool now=i&1;
        bool xia=1-now;
        dp[xia][0]=1;
        if(s[i+1]=='?'){
            for(int j=0;j<=lent;++j){
                if(!dp[now][j])continue;
                for(int k=0;k<26;++k){
                    int jnxt=ed[j][k];
                    dp[xia][jnxt]=Max(dp[xia][jnxt],dp[now][j]+(jnxt==lent));
                }
                dp[now][j]=0;
            }
        }else{
            for(int j=0;j<=lent;++j){
                if(!dp[now][j])continue;
                int jnxt=ed[j][s[i+1]-'a'];
                dp[xia][jnxt]=Max(dp[xia][jnxt],dp[now][j]+(jnxt==lent));
                dp[now][j]=0;
            }
        }
    }
    int ind=len&1;
    for(int j=0;j<=lent;++j){
        ans=Max(ans,dp[ind][j]);
    }
    cout<<ans-1<<en;
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值