题目链接:http://codeforces.com/problemset/problem/706/C
题意:给定了n个字符串,以及他们逆序之后的代价,对每个字符串可以正序输出或逆序输出,但逆序需付出代价,判断是否可以排成字典序,若可以则输出最小代价。其中 2≤n≤106 。
想法:很明显的一道dp,我们定义dp[i][j]为考虑到第i个字符是否翻转的已排成字典序的最小代价,其中j为1表示已翻转,0表示未翻转。那么转移则很好想了,详见代码。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <cmath>
#include <cstdlib>
typedef long long ll;
const int MAXN = 100000 + 100;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll dp[MAXN][2];
std::string s[MAXN], rs[MAXN];
int c[MAXN];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i){
scanf("%d", c + i);
}
for(int i = 0; i < n; ++i){
std::cin >> s[i];
rs[i] = s[i];
std::reverse(rs[i].begin(), rs[i].end());
}
memset(dp, INF, sizeof(dp));
dp[0][0] = 0;
dp[0][1] = c[0];
for(int i = 1; i < n; ++i){
if(rs[i] >= s[i - 1]){
dp[i][1] = std::min(dp[i][1], dp[i - 1][0] + c[i]);
}
if(rs[i] >= rs[i - 1]){
dp[i][1] = std::min(dp[i][1], dp[i - 1][1] + c[i]);
}
if(s[i] >= rs[i - 1]){
dp[i][0] = std::min(dp[i][0], dp[i - 1][1]);
}
if(s[i] >= s[i - 1]){
dp[i][0] = std::min(dp[i][0], dp[i - 1][0]);
}
}
ll ans = std::min(dp[n - 1][0], dp[n - 1][1]);
if(ans == INF){
std::cout << "-1" << std::endl;
}else{
std::cout << ans << std::endl;
}
return 0;
}