[题解]CF990G Easy Problem
我是被题目吸引进来的
题意
给你一个长为\(n\)的字符串\(s\)以及\(a_1..a_n\),删去第\(i\)个字符的代价为\(a_i\) 。
你需要删去一些字符(如果一开始就符合条件当然可以不删)使得剩下的串中不含子序列 \("hard"\),求最小代价。
题解
首先看到题目,想到\(DP\)(怎么D?)
设\(PD(i,A)\)为前i个字符中的子序列不包含\(A\)子序列
设\(f[i][1]\)为满足\(PD(i,"h")\)的最小代价,设\(f[i][2]\)为满足\(PD(i,"ha")\)的最小代价,设\(f[i][3]\)为满足\(PD(i,"har")\)的最小代价,设\(f[i][4]\)为满足\(PD(i,"hard")\)的最小代价
换位思考,此时到了\(f[i][j]\)\((1<=j<=4)\),相当于:
已知满足\(PD(i-1,A)\),则\(f[i][j]\)是\(PD(i,A+s)\)的最小代价(\(A\)为一个子序列,\(s\)为新增字符)
由此,我们想到状态转移方程:
1.\(s_i \neq h或a或r或d\),无需处理,直接转移
2.可以把自己干掉,就能满足条件(因为前面是\(PD(i-1,A)\)满足,所以\(PD(i,A+s)\)一定满足)
3.可以不干掉自己,让前面进一步满足\(PD(i-1,A-s)\),即可转移
综上,状态转移方程为:
if(s[i]=='ch')f[i][j]=min(f[i-1][j-1],f[i-1][j]+a[i]);
我们就会神奇地发现:可以把一维给压掉!!!
AC代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n,a[110000],f[6];
char s[110000];
int main(){
scanf("%lld\n",&n);
for(ll i=1;i<=n;i++)scanf("%c",&s[i]);
for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);
for(ll i=1;i<=n;i++){
if(s[i]=='h')f[1]+=a[i];
if(s[i]=='a')f[2]=min(f[1],f[2]+a[i]);
if(s[i]=='r')f[3]=min(f[2],f[3]+a[i]);
if(s[i]=='d')f[4]=min(f[3],f[4]+a[i]);
}
printf("%lld",f[4]);
}