Codeforces 1096D - Easy Problem - [DP]

题目链接:http://codeforces.com/problemset/problem/1096/D

题意:

给出一个小写字母组成的字符串,如果该字符串的某个子序列为 $hard$,就代表这个字符串是不好的。

现在你要删掉若干字母,使得字符串是好的,同时删除第 $i$ 个字母会使得歧义程度增加 $a[i]$,你需要让歧义程度最低,输出这个值。

题解:

$dp[i][x=0,1,2,3]$ 的状态是前 $i$ 个字母,第二维 $x$ 代表:$0$——不包含任何有可能构成 “$hard$” 的子序列;$1$——含有 “$h$” 子序列;$2$——含有 “$ha$” 子序列;$3$——含有 $har$ 子序列。

$dp[i][x=0,1,2,3]$ 记录的值当然就是歧义程度。

转移的话,$dp[i][0]$ 的转移很简单。其次,则需要分别考虑当前字符是不是 $h$、$a$、$r$,然后相应转移出 $dp[i][1]$、$dp[i][2]$、$dp[i][3]$,具体参加代码。

另外一个需要注意的是 ok?x:y 这个三目运算符外面要加括号……要不然由于加号优先级比它高,所以会把前面的加号也算在判定条件里……

讲真,刚开始想道这样设定状态,以及相应的状态转移到底对不对,心里也没底,没想到写了一发居然就1A了……

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e5+10;
int n;
char s[maxn];
ll a[maxn];
ll dp[maxn][4];
void print(int i) {
    cout<<dp[i][0]<<" "<<dp[i][1]<<" "<<dp[i][2]<<" "<<dp[i][3]<<endl;
}
int main()
{
    cin>>n;
    scanf("%s",s+1);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);

    memset(dp,0x3f,sizeof(dp));
    if(s[1]=='h')
        dp[1][0]=a[1], dp[1][1]=0;
    else
        dp[1][0]=0;
    for(int i=2;i<=n;i++)
    {
        dp[i][0]=dp[i-1][0]+((s[i]=='h')?a[i]:0ll);

        if(s[i]=='h')
            dp[i][1]=min(dp[i-1][0],dp[i-1][1]);
        else
            dp[i][1]=dp[i-1][1]+((s[i]=='a')?a[i]:0ll);

        if(s[i]=='a')
            dp[i][2]=min(dp[i-1][1],dp[i-1][2]);
        else
            dp[i][2]=dp[i-1][2]+((s[i]=='r')?a[i]:0ll);

        if(s[i]=='r')
            dp[i][3]=min(dp[i-1][2],dp[i-1][3]);
        else
            dp[i][3]=dp[i-1][3]+((s[i]=='d')?a[i]:0ll);
    }

    ll ans=INF;
    for(int i=0;i<4;i++) ans=min(ans,dp[n][i]);
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/dilthey/p/10493197.html