Problem:codeforces.com/contest/706/problem/C
题意:顺序给出 n 个字符串,不能交换顺序,但每个串都可以反转(reverse),代价为 ci,问能不能使得这些字符串从前往后字典序是从小到大的,并算出最小代价
分析:dp[2][n] 记录代价,dp[0][] 表示第不反转的情况,dp[1][] 是反转的情况
初始化 dp[0][0] = 0,dp[1][0] = c[0],其它都是 BIG(从 0 到 n-1)
然后从第2个串开始,每次都让这个串的正串、反串与上一个串的正串、反串比较,如果字典序比前面大就转移,如果当前串是反串,转移时加上反转的代价
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int maxn = 100000;
string s[maxn]; // 正串
string rs[maxn]; // 反串
long long c[maxn],dp[2][maxn];
int main()
{
int n;
cin >> n;
long long big = 1;
for(int i=0; i<n; i++)
{
cin >> c[i];
big += c[i];
}
for(int i=0; i<n; i++)
{
cin >> s[i];
rs[i] = s[i];
reverse(rs[i].begin(), rs[i].end() );
}
for(int i=0; i<n; i++)
dp[0][i] = dp[1][i] = big;
dp[0][0] = 0;
dp[1][0] = c[0];
for(int i=1; i<n; i++)
{
if( s[i] >= s[i-1] ) // 正串 vs 正串
dp[0][i] = min(dp[0][i], dp[0][i-1]);
if( s[i] >= rs[i-1] ) // 正串 vs 反串
dp[0][i] = min(dp[0][i], dp[1][i-1]);
if( rs[i] >= s[i-1] ) // 反串 vs 正串
dp[1][i] = min(dp[1][i], dp[0][i-1] + c[i]);
if( rs[i] >= rs[i-1] ) // 反串 vs 反串
dp[1][i] = min(dp[1][i], dp[1][i-1] + c[i]);
// 两个都没更新就不可能做到
if( dp[0][i] == big && dp[1][i] == big )
break;
}
long long ans = min(dp[0][n-1], dp[1][n-1]);
cout << ( ans == big ? -1 : ans ) << endl;
return 0;
}