CF1096D Easy Problem(DP)
貌似最近刷了好多的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]$ 的最大值。不能匹配到第四位。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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); }