题目链接:https://codeforc.es/contest/1096/problem/D
题目大意:有一个字符串数组,每个位置有一个权值,删掉这个字符要付出这个位置的字符的权值的代价,字符串中可能包含了 “hard” 字符序列,你要删掉一些字符使得字符串中不会出现 “hard” 子序列,求最小删除代价。
题解:考虑 “hard” 字符串,当前字符是 “d” 时,要么删掉这个 “d”,要么在 "har"里删使得 形成不了 “har”,“使得形成不了har” 和 形成不了 “hard” 是同一性质的子问题,因此可以 dp。
令 t = “hard”,s 为原串。 设状态为dp[i][j],0≤j<4 表示前 i 个字符,删掉一些字符使得不能形成:(“h”,当j = 0;“ha”,当 j = 1;“har”,当 j = 2;“hard”,当 j = 3)。
转移方程:当 s[i] == t[j] 时:
dp[i][j]=min(dp[i−1][j−1],dp[i−1][j]+a[i])
否则:
dp[i][j]=dp[i−1][j]
枚举i,j转移即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
typedef long long ll;
int n;
char s[maxn];
char t[5] = "hard";
ll a[maxn];
ll dp[maxn][5];
int main() {
scanf("%d",&n);
scanf("%s",s + 1);
for(int i = 1; i <= n; i++)
scanf("%lld",&a[i]);
memset(dp,0,sizeof dp);
for(int i = 1; i <= n; i++) {
for(int j = 0; j < 4; j++) {
dp[i][j] = dp[i - 1][j];
if(j == 0) {
if(s[i] == t[j])
dp[i][j] += a[i];
}
else {
if(s[i] == t[j])
dp[i][j] = min(dp[i - 1][j - 1],dp[i][j] + a[i]);
}
}
}
printf("%lld
",dp[n][3]);
return 0;
}