CF1096D 题解

题目链接

可爱的题目大意

给出一个长度为(n)的字符串,如果这个字符串中含有子序列(“hard”),那么这个字符串就很(hard)。你不希望这个字符串很(hard),所以想要从中删掉几个字符使他不(hard)
例:(hard)(hzazrzd)(haaaaard) 都很 (hard),而 (har)(hart)(drah)(hard)
删掉在原字符串中的第(i)个字符需要花费(a_i)的代价,求最小代价。

(Solution)

我们令(f_{i,j})表示当前(dp)到第(i)位,清到(hard)的第几位(用当前位置消掉(hard)
对于一个可能的子序列(hard),我们只需要在其中任意删掉一个字符就可以消灭整个字符串,那么有
(f_{i,j}=min(f_{i-1,j-1},f_{i-1,j}+a_i))
然后我们发现第(i)层的状态只和(i-1)层的状态有关,于是就可以省掉一维(其实省掉一维的做法更好理解?)

(Code)

#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
	typedef long long ll;
	typedef double db;
	#define pf printf
	#define pc putchar
	#define fr(i,x,y) for(register ll i=(x);i<=(y);++i)
	#define pfr(i,x,y) for(register ll i=(x);i>=(y);--i)
	#define go(x) for(ll i=head[u];i;i=e[i].nxt)
	#define enter pc('
')
	#define space pc(' ')
	#define fir first
	#define sec second
	#define MP make_pair
	const ll inf=0x3f3f3f3f;
	const ll inff=1e15;
	inline ll read()
	{
		ll sum=0,f=1;
		char ch=0;
		while(!isdigit(ch))
		{
			if(ch=='-') f=-1;
			ch=getchar();
		}
		while(isdigit(ch))
		{
			sum=sum*10+(ch^48);
			ch=getchar();
		}
		return sum*f;
	}
	inline void write(ll x)
	{
		if(x<0)
		{
			x=-x;
			pc('-');
		}
		if(x>9) write(x/10);
		pc(x%10+'0');
	}
	inline void writeln(ll x)
	{
		write(x);
		enter;
	}
	inline void writesp(ll x)
	{
		write(x);
		space;
	}
}
using namespace my_std;
const ll N=1e5+50;
ll n,a[N],f[5];
char s[N];
int main(void)
{
	n=read();
	scanf("%s",s+1);
	fr(i,1,n) a[i]=read();
	fr(i,1,n)
	{
		if(s[i]=='h') f[1]+=a[i];
		else if(s[i]=='a') f[2]=min(f[2]+a[i],f[1]);
		else if(s[i]=='r') f[3]=min(f[3]+a[i],f[2]);
		else if(s[i]=='d') f[4]=min(f[4]+a[i],f[3]);
	}
	writeln(f[4]);
	return 0;
}
原文地址:https://www.cnblogs.com/lgj-lgj/p/12672454.html