[题解]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]);
}
posted @ 2020-04-17 14:34  ZTC_ZTC  阅读(172)  评论(0编辑  收藏  举报