每天一把CF : 10-27
dp
706C 1600
题目
原题链接:https://codeforces.com/problemset/problem/706/C
思路
题目大意:给定n个字符串,有一操作,即将其反序,对第i个字符串进行反序操作需要花费c[i],现要将其按字典序排序,问最小花费是多少。
思路:针对每个字符串进行换或不换的判断。
下进行证明dp方法是正确的。即最优子问题和无后效性。
反证法:假设最后问题的解在第i个子问题(即到第i个序列)处不是最优解,即前i个字符串排列成字典序所需的花费小于最终解在第i个字符串处的花费。若假设成立,则这个花费一定小于i+1处的花费,依次类推,最终解的花费也可减少。所以由这个较小推出的最小也满足最小子问题。故假设不成立。
代码实现
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mes0(c) memset((c),0,sizeof(c))
typedef long long ll;
const int MAX = 1e5 + 5;
const ll inf = 1e15;
ll n;
ll dp[MAX][2], a[MAX];
string s[MAX], m[MAX];
int main() {
while (cin >> n) {
mes0(dp);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
cin >> s[i];
m[i] = s[i];
reverse(m[i].begin(), m[i].end());
}
for (int i = 1; i <= n; i++) {
dp[i][0] = dp[i][1] = inf;
if (s[i] >= s[i - 1]) dp[i][0] = min(dp[i][0], dp[i - 1][0]);
if (s[i] >= m[i - 1]) dp[i][0] = min(dp[i][0], dp[i - 1][1]);
if (m[i] >= s[i - 1]) dp[i][1] = min(dp[i][1], dp[i - 1][0] + a[i]);
if (m[i] >= m[i - 1]) dp[i][1] = min(dp[i][1], dp[i - 1][1] + a[i]);
}
ll ans = min(dp[n][0], dp[n][1]);
cout << (ans == inf ? -1 : ans) << endl;
}
return 0;;
}