题目大意
给你一个长为(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<bits/stdc++.h>
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;
}