Hard Problem - 每天一把CF - 2020027

63 篇文章 0 订阅
26 篇文章 0 订阅
博客讨论了如何使用动态规划解决CodeForces上的一道问题,题目要求按字典序排序字符串并计算最小花费。博主通过反证法证明了动态规划方法的正确性,并提供了代码实现。
摘要由CSDN通过智能技术生成

每天一把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;;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值