AGC054D

主要思路来自 huzhaoyang 大佬

对于两个字符串 st(保证其中每一种字符个数相同),定义 st 的相对逆序对数为 s 得到 t 的最少交换次数,显然同种字符相对顺序保持不变,因此即依次编号后的逆序对数。

问题不妨看作构造合法字符串 t 使得 st 的相对逆序对数最小,定义 fS(s)s 仅保留 S 中的字符后所得到的字符串,那么有以下两个结论:

结论 1:当 S={(,)} 时,若 t 是使得 st 相对逆序对数最小的合法字符串,则 fS(t) 也是使得 fS(s)fS(t) 相对逆序对数最小的合法字符串

结论 2:当 S={o,x} 时,若 t 是使得 st 相对逆序对数最小的合法字符串,则 fS(s)=fS(t)

由此,不妨先求出 S={(,)} 时的 fS(t),进而即将 ox 从左到右依次插入,显然这可以用一个二维 DP 计算,条件为 x 之前左括号数严格大于右括号数,计算答案考虑逆序对数即可。

虽然但是我不会证结论。

Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 8005;
int n, n1, n2;
int ans;
int p1[N], p2[N];
char s[N], s1[N], s2[N];
int f[N][N];
int pre1[N], pre2[N], preo[N], prex[N];
int sum1[N], sum2[N], sumo[N], sumx[N];

void chkmin(int &a, int b) { if (a > b) a = b; }

int main() {
	scanf("%s", s + 1), n = strlen(s + 1);
	for (int i = 1; i <= n; ++i) {
		if (s[i] > 'a') s2[++n2] = s[i], p2[n2] = i;
		else s1[++n1] = s[i];
		pre1[i] = pre1[i - 1] + (s[i] == '(');
		pre2[i] = pre2[i - 1] + (s[i] == ')');
		preo[i] = preo[i - 1] + (s[i] == 'o');
		prex[i] = prex[i - 1] + (s[i] == 'x');
	}
	for (int i = 1, cur = 0; i <= n1; ++i) {
		if (s1[i] == '(') ++cur; else --cur;
		if (cur < 0) {
			cur = 1;
			for (int j = i + 1; j <= n1; ++j) if (s1[j] == '(') {
				swap(s1[i], s1[j]), ans += j - i; break;
			}
		}
	}
	for (int i = 1, P1 = 0, P2 = 0; i <= n1; ++i) {
		if (s1[i] == '(') {
			do {
				++P1;
			} while (s[P1] != '(');
			p1[i] = P1;
		}
		else {
			do {
				++P2;
			} while (s[P2] != ')');
			p1[i] = P2;
		}
	}
	for (int i = 1; i <= n1; ++i) {
		sum1[i] = sum1[i - 1] + (s1[i] == '(');
		sum2[i] = sum2[i - 1] + (s1[i] == ')');
	}
	for (int i = 1; i <= n2; ++i) {
		sumo[i] = sumo[i - 1] + (s2[i] == 'o');
		sumx[i] = sumx[i - 1] + (s2[i] == 'x');
	}
	memset(f, 0x3f, sizeof f), f[0][0] = 0;
	for (int i = 0, cur = 0; i <= n1; ++i) {
		for (int j = 0; j <= n2; ++j) {
			if (i < n1) chkmin(f[i + 1][j], f[i][j] + max(0, sumo[j] - preo[p1[i + 1]]) + max(0, sumx[j] - prex[p1[i + 1]]));
			if (j < n2 && (cur || s2[j + 1] == 'o')) chkmin(f[i][j + 1], f[i][j] + max(0, sum1[i] - pre1[p2[j + 1]]) + max(0, sum2[i] - pre2[p2[j + 1]]));
		}
		if (s1[i + 1] == '(') ++cur; else --cur;
	}
	printf("%d", ans + f[n1][n2]);
	return 0;
}
posted @   Kobe303  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话
点击右上角即可分享
微信分享提示