CodeForces 706C Hard problem(dp)

CodeForces 706C Hard problem

  • 题目大意:有n个字符串,你可以对每个字符串进行翻转,翻转一次需要花费一定费用,问经过几次翻转后,使得字符串从小到大排列,且花费最少。
  • 思路:贪心肯定不行,考虑dp。每个字符串都有两种状态:翻转和没有翻转。 d p [ i ] [ j ] dp[ i ] [ j ] 表示前 i i 个符合要求的字符串的最小费用。当 j = 1 j=1 时表示第 i i 个字符串翻转,当 j = 0 j=0 时表示第 i i 个字符串没有翻转。当枚举 d p [ i ] [ k ] dp[i][k] k k 时先枚举 d p [ i 1 ] [ j ] dp[i-1][j] j j ,因为 d p [ i 1 ] [ j ] dp[i-1][j] d p [ 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])
  • 代码:
#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;
}
发布了34 篇原创文章 · 获赞 7 · 访问量 1872

猜你喜欢

转载自blog.csdn.net/qq_43628761/article/details/101121605