CodeForces - 1465D.Grime Zoo (贪心+思维)

题意

给出一个包含 0 1 ? 0 1 ? 0 1 ? 的序列 每个子序列 01 01 01会增加 x x x点愤怒值,每个子序列 10 10 10会增加 y y y点愤怒值

用 0 1 0 1 0 1代替所有的 ? ? ? 使得最终的愤怒值最小

思路

先用 1 1 1 代替所有的 ? ? ? 求出每个位置前缀和后缀中 1 0 ? 1 0 ? 1 0 ? 的数量 计算得到当前愤怒值 $re

如果 x < y x < y x<y 贪心地使得 01 01 01 多 10 10 10 少 即从前往后地将 ? ? ? 用 0 0 0 替换 遍历每种情况 求最小值

如果 x > y x > y x>y 贪心地使得 10 10 10 多 01 01 01 少 即从后往前地将 ? ? ? 用 1 1 1 替换 遍历每种情况 求最小值

p s : ps: ps: 在求最小值的过程中 刚开始我用

int x = vec[i];

导致变量名重复 de了半天bug愣是没找到错在哪 😅

代码

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define mod 1000000007
using namespace std;

typedef long long LL;
typedef pair<int, int>PII;
inline LL gcd(LL a, LL b) {
          
    return b ? gcd(b, a % b) : a; }

const int N = 100010;

LL x, y;
char s[N];
int st[N][3], ed[N][3]; //记录前缀、后缀中 0、1、?的个数
vector<int>vec;

void solve() {
          
   
	scanf("%s", s + 1);
	cin >> x >> y;
	int len = strlen(s + 1);
	for (int i = 1; i <= len; ++i) {
          
    //前缀
		st[i][0] = st[i - 1][0];
		st[i][1] = st[i - 1][1];
		st[i][2] = st[i - 1][2];
		if (s[i] == 0)st[i][0]++;
		else if (s[i] == 1)st[i][1]++;
		else {
          
   
			vec.push_back(i);
			st[i][2]++;
		}
	}

	for (int i = len; i >= 1; --i) {
          
    //后缀
		ed[i][0] = ed[i + 1][0];
		ed[i][1] = ed[i + 1][1];
		ed[i][2] = ed[i + 1][2];
		if (s[i] == 0)ed[i][0]++;
		else if (s[i] == 1)ed[i][1]++;
		else ed[i][2]++;
	}

	LL sum0 = 0, sum1 = 0;
	LL ans = 0;

	for (int i = 1; i <= len; ++i) {
          
    //先求出把 ? 当作 1 时的的“愤怒值”
		if (s[i] == 0) {
          
   
			ans += sum1 * y;
			sum0++;
		}
		else {
          
   
			ans += sum0 * x; //把 ? 先看做是 1
			sum1++;
		}
	}

	LL res = ans;
	if (x < y) {
          
    //把 ? 当作 1 尽量放在前面 从后往前 将 ? 用 0 替换 遍历每种情况求最小值
		for (int i = 0; i < vec.size(); ++i) {
          
   
			int idx = vec[i];
			res = res - (st[idx - 1][0] + st[idx - 1][2]) * x - ed[idx + 1][0] * y;
			res = res + st[idx - 1][1] * y + (ed[idx + 1][1] + ed[idx + 1][2]) * x;
			ans = min(res, ans);
		}

	}
	else {
          
    //把 ? 当作 1 尽量放在后面 从前往后 将 ? 用 0 替换 遍历每种情况求最小值
		for (int i = vec.size() - 1; i >= 0; --i) {
          
   
			int idx = vec[i];
			res = res - st[idx - 1][0] * x - (ed[idx + 1][0] + ed[idx + 1][2]) * y;
			res = res + (st[idx - 1][1] + st[idx - 1][2]) * y + ed[idx + 1][1] * x;
			ans = min(res, ans);
		}
	}

	cout << ans << endl;





}
int main() {
          
   
	//int t; cin >> t;
	//while (t--)
	solve();

	return 0;
}
经验分享 程序员 微信小程序 职场和发展