Codeforces Round #367 (Div. 2) Hard problem

Hard problem

题意:

有n个字符串,对第i个字符串进行反转操作代价为ci。
要使n个字符串按照字典序从小到大排列,最小的代价是多少。

题解:

反转就是reverse操作,比如说45873反转之后只能是37845,不能是别的,当时就这没有理解好,所以没继续去想,其实可以假设这样,之后来一发的,如果当时这样不就对了嘛。
一行只有反转或不反转,要求最小代价,有道01背包的意思,所以就要dp试试,dp[i]代表第i的串的最小代价,但是怎么继续推呢?,没有办法,就再多开一维,另一维只要代表2个状态就好,用0表示没有反转,1表示已经反转了,那么定义就如下了:

dp[i][0]代表前i个串有序且第i个串不反转的代价

dp[i][1]代表前i个串有序且第i个串反转的代价

初始化 dp[0][0]=0,dp[0][1] = c[0]

然后当字典序满足有小到大时进行递推

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
#define cle(a,val) memset(a,(val),sizeof(a))
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 100000 + 5 ;
int n, c[MAXN];
ll dp[MAXN][2];
string s[MAXN];
void ini()
{
    for(int i = 0; i < MAXN; i++)
        for(int j = 0; j < 2; j++)
            dp[i][j] = LINF;
    dp[0][0] = 0;
    dp[0][1] = c[0];
}
void Solve()
{
    cin >> n;
    for(int i = 0; i < n; i++)
        cin >> c[i];
    for(int i = 0; i < n; i++)
        cin >> s[i];
    ini();
    for(int i = 1; i < n; i++)
    {
        string s1 = s[i - 1];
        reverse(s1.begin(), s1.end());
        string s2 = s[i];
        reverse(s2.begin(), s2.end());
        if(s[i] >= s[i - 1]) dp[i][0] = min(dp[i][0], dp[i - 1][0]);
        if(s[i] >= s1) dp[i][0] = min(dp[i][0], dp[i - 1][1] );
        if(s2 >= s[i - 1]) dp[i][1] = min(dp[i][1], dp[i - 1][0] + c[i]);
        if(s2>=s1) dp[i][1]=min(dp[i][1],dp[i-1][1]+c[i]);
    }
    if(dp[n-1][0] != LINF || dp[n-1][1] != LINF)
    {
        cout << min(dp[n-1][0], dp[n-1][1]) << endl;
    }
    else
    {
        puts("-1");
    }
}
int main()
{
    Solve();
    return 0;
}
原文地址:https://www.cnblogs.com/s1124yy/p/5765662.html