首页 > 其他分享 >Codeforces Round #821 (Div. 2) - D2. Zero-One (Hard Version)

Codeforces Round #821 (Div. 2) - D2. Zero-One (Hard Version)

时间:2022-09-21 00:26:55浏览次数:109  
标签:return int ll Hard Codeforces dfs pos include 821

区间DP

Problem - D2 - Codeforces

题意

给一个长度为 \(n(5<=n<=5000)\) 的 01串,每次操作可选择一个 \(l,r(l<r)\), 把 \(s[l],s[r]\) 反转。如果 \(l+1==r\), 花费为 x,否则为 y

求把所有的 1 变成 0 的最小代价

思路

  1. 根据 D1 的提示,要分类讨论,当 x >= y 时很容易贪心求解

  2. 当 x < y 时,结合数据范围,可以尝试区间dp

  3. 可以先把每个 1 的位置记下来,存到 \(pos\) 数组中,设共有 m 个 1 (m为偶数,奇数直接返回-1)

  4. 记 \(f[l][r]\) 为将第 \(l\) 个 1 到第 \(r\) 个 1 全部清零,有三种策略

    1. \(cost(l,l+1)+f[l+2][r]\)
    2. \(cost(r-1,r)+f[l][r-2]\)
    3. \(cost(l,r)+f[l+1][r-1]\)

    这里 \((l,l+1)与(r-1,r)\) 必定至少结合一组,因为如果都与不相邻的结合,不管用哪种操作都没有与更近的结合更优(因为x<y)

  5. 记忆化搜索即可

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cmath>

using namespace std;
#define endl "\n"

typedef long long ll;
typedef pair<int, int> PII;

const int N = 5e3 + 10;
int n;
ll x, y;
string s;
int a[N], b[N], c[N];
int d[3];
ll f[N][N];
vector<int> pos;
ll dfs(int l, int r)
{
	if (l > r)
		return 0;
	if (f[l][r] != -1)
		return f[l][r];
	ll ans1 = dfs(l + 2, r) + min(y, (pos[l+1] - pos[l]) * x);
	ll ans2 = dfs(l, r - 2) + min(y, (pos[r] - pos[r-1]) * x);
	ll ans3 = dfs(l + 1, r - 1) + min(y, (pos[r] - pos[l]) * x);
	return f[l][r] = min({ans1, ans2, ans3});
}
ll solve()
{
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		cnt += c[i];
	if (cnt & 1)
		return -1;
	if (x >= y)
	{
		if (cnt != 2)
			return cnt / 2 * y;
		int t = 0;
		for (int i = 1; i <= n; i++)
			if (c[i] == 1)
				d[++t] = i;
		if (d[1] + 1 == d[2])
			return min(x, 2 * y);
		return y;
	}
	pos.clear();
	pos.push_back(-1);
	for (int i = 1; i <= n; i++)
		if (c[i] == 1)
			pos.push_back(i);
	int m = pos.size() - 1;
	for (int i = 0; i <= m; i++)
		for (int j = 0; j <= m; j++)
			f[i][j] = -1;
	return dfs(1, m);
}
int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while(T--)
	{
		cin >> n >> x >> y;
		cin >> s;
		s = " " + s;
		for (int i = 1; i <= n; i++)
			a[i] = s[i] - '0';
		cin >> s;
		s = " " + s;
		for (int i = 1; i <= n; i++)
			b[i] = s[i] - '0';
		for (int i = 1; i <= n; i++)
			c[i] = a[i] ^ b[i];
		cout << solve() << endl;
	}
    return 0;
}

标签:return,int,ll,Hard,Codeforces,dfs,pos,include,821
From: https://www.cnblogs.com/hzy717zsy/p/16714167.html

相关文章

  • Codeforces Round #807 (Div. 2) - D. Mark and Lightbulbs
    思维Problem-D-Codeforces题意给两个长度为\(n(3<=n<=2*10^5)\)的01串s与t,求最小操作次数,使s变成t;不存在则输出-1操作为:对于2<=i<=n-1,若\(s_......
  • Codeforces Round #820 (Div. 3) G. Cut Substrings
    DPProblem-G-Codeforces题意给一个长度为\(n(1<=n<=500)\)的主串s,一个长度为\(m(1<=m<=500)\)的模式串t,每次可以将当前的s中与t相同的子串变成一串"."(如......
  • Codeforces Round #821 (Div. 2) ABCD1
    A.ConsecutiveSumhttps://codeforces.com/contest/1733/problem/A题目大意:给定一个长度为n的数组a。最多可以执行k次以下操作:选择两个指数i和j,其中imodk=jmodk......
  • Codeforces Round #821(Div.2) (A-C) 题解
    CodeforcesRound#821(Div.2)(A-C)  A.ConsecutiveSum大致题意给定一组共n个数据,如果俩个数的下标在modk意义下同余,则可以交换a[I]和a[j] ,求操作后一段......
  • Codeforces Round #821 (Div. 2)(持续更新)
    Preface唉LOL打到一半被迫营业开打,感觉这算是第一次自己认真的在线打CF,以我的老年人手速感觉要罚时飞起了10:35开始打到12:10顶不住了睡觉去了,E大概看了个题感觉挺有意思的......
  • D2. Zero-One (Hard Version)
    题意给定\(n,x,y\)和两个01串,字符串的长度为\(n\),现在你可以选择一个\(l\)和\(r\)(\(1\leq{l}<{r}\leq{n}\)),将\(a_l\)变成\(1-a_l\),将\(a_r\)变成\(1-a_r\),\(l+1=r\),则代......
  • Codeforces Round #819 (Div. 1 + Div. 2) and Grimoire of Code Annual Contest 2022
    Preface明天的CF一定打啊(绝对不咕),今天白天补现代作业,英语作业到哭,而且还要准备四六级,每天逼着自己背单词A.MainakandArray不难发现换中间的数不会影响答案,因此操作......
  • Codeforces Round #821 D2
    D2.Zero-One(HardVersion)我们由D1可知当我们的y小于x/2时我们可以用2y来减小相邻的cost那我们考虑要是y比较大的时候我们也可以用多个x来减小cost我们可以轻松的......
  • Codeforces Round #821 (Div. 2)
    CodeforcesRound#821(Div.2)C.ParityShuffleSorting题目大意每次操作可以选择l,r,如果\(a_l+a_r\)是奇数可以让\(a_l=a_r\),否则可以让\(a_l=a_r\),要求使用不超过n......
  • Codeforces #821 Div2(A~D2)题解
    CF#821Div2AConsecutiveSum题目:​ 选择\(i\)和\(j\),如果\(j=i+xk(x=R)\),可以交换\(i,j\)。任意选择一段长度为k的相加。思路:​ 题目等价于在下标\(mod\)k相同......