CF1096D Easy Problem(DP)

貌似最近刷了好多的CF题……

题目链接:CF原网  洛谷

题目大意:有一个长度为 $n$ 的字符串 $s$,删除第 $i$ 个字符需要代价 $a_i$。问使得 $s$ 不含有子序列(不是子串)"hard" 的最小花费。

$1\le n\le 10^5,1\le a_i\le 10^9$,$s$ 只包含小写字母。


其实就是一简单DP。

$dp[i][j]$ 表示考虑到 $s$ 的前缀 $i$,目前最远能匹配到 "hard" 的位置,的最小花费。

比如,$dp[3][2]$ 表示考虑 $s$ 的前三个字符,目前最远能匹配到 "ha" 的最小花费。

初始状态 $dp[0][j]=0$。

转移:如果 $s[i]\neq hard[j+1]$,说明如果删不删 $i$ 都不会使 $j$ 变大,那么 $dp[i][j]=\min(dp[i-1][j])$。

否则,如果选择删掉 $i$,$dp[i][j]=\min(dp[i-1][j]+a[i])$。

否则,就是不删掉 $i$。$dp[i][j]=\min(dp[i-1][j-1])$。注意判断边界 $j=0$。

答案就是 $dp[n][0/1/2/3]$ 的最大值。不能匹配到第四位。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const char hard[6]="*hard";    //hard[0]表示什么都没有,hard[i]表示第i个字符
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define ROF(i,a,b) for(int i=(a);i>=(b);i--)
#define MEM(x,v) memset(x,v,sizeof(x))
inline int read(){
    char ch=getchar();int x=0,f=0;
    while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return f?-x:x;
}
int n,a[maxn];
char str[maxn];
ll dp[maxn][4];
int main(){
    n=read();
    scanf("%s",str+1);
    FOR(i,1,n) a[i]=read();
    MEM(dp,0x3f);
    FOR(j,0,3) dp[0][j]=0;
    FOR(i,1,n) FOR(j,0,3){
        if(str[i]!=hard[j+1]) dp[i][j]=min(dp[i][j],dp[i-1][j]);    //不会匹配更远,不删
        else{
            dp[i][j]=min(dp[i][j],dp[i-1][j]+a[i]);    //删掉
            if(j) dp[i][j]=min(dp[i][j],dp[i-1][j-1]);    //不删
        }
    }
    ll ans=LLONG_MAX;
    FOR(j,0,3) ans=min(ans,dp[n][j]);    //取最小值
    printf("%lld\n",ans);
}
View Code

猜你喜欢

转载自www.cnblogs.com/1000Suns/p/10361376.html