Codeforces 808G Anthem of Berland(KMP+基础DP)

题意

给定一个字符串 \(s\) ,一个字符串 \(t\) ,其中 \(s\) 包含小写字母和 "?" ,\(t\) 只包含小写字母,现在把 \(s\) 中的问号替换成任意的小写字母,求 \(t\) 最多在 \(s\) 中出现多少次,\(t\) 可以互相覆盖。

\(1 \leq |s| \leq 10^5\)

\(1 \leq |t| \leq 10^5\)

\(1 \leq |s|\cdot|t| \leq 10^7\)

思路

由于 \(|s|\cdot|t| \leq 10^7\) ,那么用 \(dp[i][j]\) 表示 \(s\) 匹配到第 \(i\) 位,\(t\) 匹配到第 \(j\) 位时的最多出现次数,如果出现"?",就枚举是哪个字符。需要预处理出在哪一位遇到什么字符,接下来要到哪里匹配的信息。

我们设 \(F[i][j]\) 为匹配到模式串 \(P\) 的第 \(i\) 位,遇到 \(j\) 字符,下一位应该匹配 \(P\) 的哪一位。这个数组可以和 \(f\) 数组一起交替处理,使两者复杂度都得到保证。这个数组的思想也很重要,在后面的AC自动机中也有体现。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long LL;
using namespace std;
const int N=1e5+5;
const int NN=2e7+5;
char T[N],P[N];
int f[N],F[N][30];  //F[i][j]表示匹配到第i位为'a'+j,下一位应匹配哪一位
int dp[NN];
int n,m;
#define dp(i,j) dp[(i)*(m+5)+j]

int main()
{
    scanf("%s%s",T+1,P+1);
    n=strlen(T+1),m=strlen(P+1);

    f[1]=f[2]=1;FOR(i,0,25)F[1][i]=1+(P[1]-'a'==i);
    FOR(i,2,m)
    {
        f[i+1]=F[f[i]][P[i]-'a'];
        FOR(j,0,25)
        {
            if(P[i]-'a'==j)F[i][j]=i+1;
            else F[i][j]=F[f[i]][j];
        }
    }

    FOR(i,1,n+1)FOR(j,1,m+1)dp(i,j)=-1;
    dp(1,1)=0;
    FOR(i,1,n)FOR(j,1,m)if(~dp(i,j))
    {
        if(T[i]!='?')
        {
            int J=F[j][T[i]-'a'];
            if(J==m+1)dp(i+1,f[J])=max(dp(i+1,f[J]),dp(i,j)+1);
            else dp(i+1,J)=max(dp(i+1,J),dp(i,j));
        }
        else
        {
            FOR(k,0,25)
            {
                int J=F[j][k];
                if(J==m+1)dp(i+1,f[J])=max(dp(i+1,f[J]),dp(i,j)+1);
                else dp(i+1,J)=max(dp(i+1,J),dp(i,j));
            }
        }
    }
    int ans=0;
    FOR(i,1,m)ans=max(ans,dp(n+1,i));
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/Paulliant/p/10204963.html

时间: 2024-11-20 02:57:50

Codeforces 808G Anthem of Berland(KMP+基础DP)的相关文章

Codeforces 808G. Anthem of Berland

G. Anthem of Berland 题意:给两串S,T.S由"a-z","?"组成,T由"a-z"组成.你可以钦定这些"?",询问 T 在 S 中最多出现次数. 想法:考虑Dp,需要记录的是匹配到 T 多长的前缀.于是设$F[i][j]$表示 S 前 j 位现匹配 T 前i位的最多完整匹配次数.转移需要求出$nx[i][v]$表示 T 前i位后面接上v能匹配的最长前缀,用KMP求一下. Code #include <

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

基础dp

队友的建议,让我去学一学kuangbin的基础dp,在这里小小的整理总结一下吧. 首先我感觉自己还远远不够称为一个dp选手,一是这些题目还远不够,二是定义状态的经验不足.不过这些题目让我在一定程度上加深了对dp的理解,但要想搞好dp,还需要多多练习啊. HDU - 1024 开场高能 给出一个数列,分成m段,求这m段的和的最大值,dp[i][j]表示遍历到第i个数,已经划分了j段,对于每一个数有两种决策,加入上一个区间段,自己成为一个区间段,故dp[i][j] = max(dp[i-1][j]+

POJ 3616 Milking Time 基础DP

Milking Time Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5743   Accepted: 2401 Description Bessie is such a hard-working cow. In fact, she is so focused on maximizing her productivity that she decides to schedule her next N (1 ≤ N ≤

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

CodeForces 258B Little Elephant and Elections 数位DP

前面先用数位DP预处理,然后暴力计算组合方式即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

Codeforces 219D. Choosing Capital for Treeland (树dp)

题目链接:http://codeforces.com/contest/219/problem/D 树dp 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio&

CSU 1620: A Cure for the Common Code(KMP+区间DP)

Description Input Output Sample Input abcbcbcbca abbbcdcdcdabbbcdcdcd 0 Sample Output Case 1: 7 Case 2: 11 HINT 题意:给一个小写子母的串,相邻相同的子串可以合在一起,问这个串合并后最短可得多长. 解题:KMP & 区间DP #include<stdio.h> #include<string.h> const int N = 505; int next1[N]; c