题目传送门
题目大意
给你一个长为\(n\)的字符串\(s\)以及\(a_{1 \ldots n}\),删去第\(i\)个字符的代价为\(a_i\),你需要删去一些字符(如果一开始就符合条件当然可以不删)使得剩下的串中不含子序列 "\(hard\)"(子序列不需要连续),求最小代价
思路
典型的\(dp\)
定义状态:
设\(f_{i,j}\)为\(s\)字符串的前\(i\)个字符匹配到\(hard\)的第\(j\)个字母所花的最小代价
转移:
先看\(s_i\)等不等于\(hard\)的第\(j\)位
如果不等于,则\(f_{i,j}=f_{i-1,j}\)
否则,就有两种选择:一种就是不继续去掉\(hard\)的第\(j\)位,一种就是继续去掉。这两者之间取\(min\),就是\(f_{i,j}\)了,所以\(f_{i,j}=min(f_{i-1,j-1},f_{i-1,j}+a_i)\)
注意
本题卡 \(long\) \(long\) ,需注意
代码
#include
using namespace std;
long long n,a[100001],f[100001][5],ans;
char s[100001],c[5]={' ','h','a','r','d'};
int main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++) scanf(" %c",&s[i]);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
memset(f,0x7f7f7f7f,sizeof(f));
for(int i=1;i<=4;i++) f[0][i]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=4;j++){
if(s[i]!=c[j]) f[i][j]=f[i-1][j];
else f[i][j]=min(f[i-1][j-1],f[i-1][j]+a[i]);
}
}
ans=min(f[n][1],min(f[n][2],min(f[n][3],f[n][4])));
printf("%lld",ans);
return 0;
}