CodeForces 706C Hard problem
- 题目大意:有n个字符串,你可以对每个字符串进行翻转,翻转一次需要花费一定费用,问经过几次翻转后,使得字符串从小到大排列,且花费最少。
- 思路:贪心肯定不行,考虑dp。每个字符串都有两种状态:翻转和没有翻转。 d p [ i ] [ j ] dp[ i ] [ j ] dp[i][j]表示前 i i i个符合要求的字符串的最小费用。当 j = 1 j=1 j=1时表示第 i i i个字符串翻转,当 j = 0 j=0 j=0时表示第 i i i个字符串没有翻转。当枚举 d p [ i ] [ k ] dp[i][k] dp[i][k]的 k k k时先枚举 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]的 j j j,因为 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j]是 d p [ i ] [ k ] dp[i][k] dp[i][k]的子问题。
- 转移方程: d p [ i ] [ k ] = m i n ( d p [ i ] [ k ] , d p [ i − 1 ] [ j ] + k ∗ a [ i ] ) dp[i][k]=min(dp[i][k],dp[i-1][j]+k*a[i]) dp[i][k]=min(dp[i][k],dp[i−1][j]+k∗a[i])
- 代码:
#include <time.h>
#include <string.h>
#include <algorithm>
#include <stack>
#include <vector>
#include <set>
#include <iostream>
#include <queue>
#include <string>
#include <map>
#include <math.h>
#define mid(l,r) (( l + r ) / 2)
#define lowbit(x) (( x & ( - x )))
#define lc(root) ( ( root * 2 ) )
#define rc(root) ( ( root * 2 + 1 ) )
#define me(array,x) (memset( array , x , sizeof( array ) ) )
typedef long long LL;
using namespace std;
const LL inf = 1e18;
const int mod = 1e9 + 7;
const int maxn = 1e5+10;
int n;
int a[maxn];
string s[maxn][2];
LL dp[maxn][2];
int main()
{
scanf("%d",&n);
for(int i = 1 ; i <= n ; i++)
scanf("%d",&a[i]);
dp[0][0] = dp[0][1] = 0;
for(int i = 1 ; i <= n ; i++)
{
cin>>s[i][0];
s[i][1] = s[i][0];
dp[i][0] = dp[i][1] = 1e18;
reverse(s[i][1].begin(),s[i][1].end());
for(int j = 0 ; j <= 1 ; j++)
{
for(int k = 0 ; k <= 1 ; k++)
{
if(s[i][k] >= s[i-1][j])
dp[i][k] = min(dp[i][k] , dp[i-1][j] + (k*a[i]));
}
}
}
LL ans = min(dp[n][0],dp[n][1]);
printf("%lld\n",ans == 1e18?-1:ans);
return 0;
}