Codeforces 1096D (DP)

Codeforces 1095F
题意:给定字符串$s$,每个位有一个权值,删掉一个位代价为这个权值。请求出最小使得字符串不包含子序列hard的代价。

最优化问题想到DP,并且这题类似于 Bzoj 1030 AC自动机。
这里是一个匹配类状态的 DP,设$dp(i,j)$为前$i$位,$j=0$表示没有匹配,$j=[1,3]$表示匹配到了前缀h, ha, har的最小代价。

转移则

dp[0][0] = 0;
for (LL j = 0; j < 4; ++j) dp[i][j] = dp[i - 1][j];
for (LL i = 1; i <= n; ++i) {
  if (s[i] == 'h') {
      dp[i][0] = dp[i - 1][0] + a[i]; //  将 `h` 删去
      dp[i][1] = min(min(dp[i - 1][0], dp[i - 1][1]), dp[i - 1][1] + a[i]); // 不动或者将 `h` 删去
  }
  if (s[i] == 'a') {
      dp[i][1] = dp[i - 1][1] + a[i]; //  将 `a` 删去
      dp[i][2] = min(min(dp[i - 1][1], dp[i - 1][2]), dp[i - 1][2] + a[i]); // 不动或者将 `a` 删去
  }
  if (s[i] == 'r') {
      dp[i][2] = dp[i - 1][2] + a[i]; //  将 `r` 删去
      dp[i][3] = min(min(dp[i - 1][2], dp[i - 1][3]), dp[i - 1][3] + a[i]); // 不动或者将 `r` 删去
  }
  if (s[i] == 'd') {
      dp[i][3] = dp[i - 1][3] + a[i]; //  将 `d` 删去
  }
}

其实中间转移不需要dp[i - 1][3], dp[i - 1][3] + a[i],因为$a_i \geq 0$,所以直接写即可。

知识点:
1、匹配类状态的 DP

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;

namespace flyinthesky {

    LL n, a[100000 + 5], dp[100000 + 5][5], INF = 4223372036854775808ll;
    char s[100000 + 5];

    void clean() {
    }
    int solve() {
        clean();
        cin >> n;
        scanf("%s", s + 1);
        for (LL i = 1; i <= n; ++i) scanf("%lld", &a[i]);

        for (LL i = 0; i <= n; ++i)
        for (LL j = 0; j < 5; ++j) dp[i][j] = INF;
        dp[0][0] = 0;

        for (LL i = 1; i <= n; ++i) {
            for (LL j = 0; j < 4; ++j) dp[i][j] = dp[i - 1][j];
            if (s[i] == 'h') {
                dp[i][0] = dp[i - 1][0] + a[i];
                //dp[i][1] = min(min(dp[i - 1][0], dp[i - 1][1]), dp[i - 1][1] + a[i]);
                dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]);
            }
            if (s[i] == 'a') {
                dp[i][1] = dp[i - 1][1] + a[i];
                //dp[i][2] = min(min(dp[i - 1][1], dp[i - 1][2]), dp[i - 1][2] + a[i]);
                dp[i][2] = min(dp[i - 1][1], dp[i - 1][2]);
            }
            if (s[i] == 'r') {
                dp[i][2] = dp[i - 1][2] + a[i];
                //dp[i][3] = min(min(dp[i - 1][2], dp[i - 1][3]), dp[i - 1][3] + a[i]);
                dp[i][3] = min(dp[i - 1][2], dp[i - 1][3]);
            }
            if (s[i] == 'd') {
                dp[i][3] = dp[i - 1][3] + a[i];
            }
        }
        printf("%lld", min(min(dp[n][0], dp[n][1]), min(dp[n][2], dp[n][3])));
        return 0;
    }
}
int main() {
    flyinthesky::solve();
    return 0;
}
------ 本文结束 ------