Codeforces Round 1026 (Div. 2)


A. Fashionable Array

题意:删除最少的数,使得最大值减最小值是偶数。

\(n\)很小,暴力枚举。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    std::ranges::sort(a.begin(), a.end());
    int ans = n;
    for (int i = 0; i < n; ++ i) {
    	for (int j = i; j < n; ++ j) {
    		if ((a[i] + a[j]) % 2 == 0) {
    			ans = std::min(ans, i + n - 1 - j);
    		}
    	}
    }
    std::cout << ans << "\n";
}

B. Down with Brackets

题意:给你一个合法的括号序列,你要恰好删掉一个左括号和一个右括号,判断能不能让序列不平衡。

upd:
如果某个前缀的左右括号个数相等,那么可以删掉这个前缀部分中的一个左括号,然后还要删一个右括号,需要删后面的,判断后面有没有右括号就行。
已更正题解,之前说删右括号找后面的左括号的做法是错的。一个前缀是平衡的,那么这个前缀后面的部分也是平衡的。那么后面的部分肯定又有左括号又有右括号。其实只要判断当前位置是不是最后一个位置就行。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    int p = s.find_last_of(')');
    for (int i = 0, cnt = 0; i < p; ++ i) {
    	if (s[i] == '(') {
    		++ cnt;
    	} else {
    		-- cnt;
    	}

    	if (cnt == 0) {
    		std::cout << "YES\n";
    		return;
    	}
    }
    std::cout << "NO\n";
}

C. Racing

题意:\(h\)从零开始,每次加一或加零,但有些地方需要你来决定。需要满足\(l_i \leq h_i \leq r_i\)

从左到右模拟,如果不是\(-1\)就加上,否则把这个位置存下来。到了\(h < l_i\)的时候,就把前面的\(-1\)从大到小改成\(1\),把\(h\)改成\(l_i\)。最后模拟一遍判断是不是都合法。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> a[i];
    }

    std::vector<int> l(n + 1), r(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> l[i] >> r[i];
    }

    std::vector<int> b;
    std::vector<int> h(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	h[i] = h[i - 1];
    	if (a[i] != -1) {
    		h[i] += a[i];
    	} else {
			b.push_back(i);
    	}

    	if (h[i] > r[i]) {
    		std::cout << -1 << "\n";
    		return;
    	}

    	if (h[i] < l[i]) {
    		int k = l[i] - h[i];
    		if (b.size() < k) {
    			std::cout << -1 << "\n";
    			return;
    		}


    		for (int j = k; j >= 1; -- j) {
    			int u = b.back(); b.pop_back();
    			a[u] = 1;
    		}

    		h[i] = l[i];
    	}
    }

    for (int i = 1, h = 0; i <= n; ++ i) {
    	if (a[i] == -1) {
    		a[i] = 0;
    	}

    	h += a[i];
    	if (h < l[i] || h > r[i]) {
    		std::cout << -1 << "\n";
    		return;
    	}
    }

    for (int i = 1; i <= n; ++ i) {
    	std::cout << a[i] << " \n"[i == n];
    }
}

D. Fewer Batteries

题意:一个有向无环图,边\((u, v)\)\(u < v\)。每到一个点\(u\)可以增加\([0, b_u]\)的值。对于一条边权为\(w\)的边,想要通过需要值大于等于\(w\)。求从\(1\)\(n\)结束时最小的值。

显然如果较小的值可以达到\(n\),那么更大的值也可以。那么可以二分答案。
然后进行\(dp\)\(f[1] = \min(mid, b[1])\)。从左到右,每条边\((u, v)\)更新\(f[v]\)的值。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> b(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> b[i];
    }

    std::vector<std::vector<std::pair<int, int>>> adj(n);
    std::vector<int> in(n);
    for (int i = 0; i < m; ++ i) {
    	int u, v, w;
    	std::cin >> u >> v >> w;
    	-- u, -- v;	
    	adj[u].emplace_back(v, w);
    }

    auto check = [&](int limit) -> bool {
		std::vector<int> f(n, -1);
		f[0] = std::min(limit, b[0]);
		for (int u = 0; u < n; ++ u) {
			for (auto & [v, w] : adj[u]) {
				if (f[u] >= w) {
					f[v] = std::max(f[v], std::min(limit, f[u] + b[v]));
				}
			}
		}    	

		return f[n - 1] != -1;
    };

    int l = 0, r = 1e9;
    while (l < r) {
    	int mid = l + r >> 1;
    	if (check(mid)) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }

    if (!check(l)) {
    	std::cout << -1 << "\n";
    } else {
    	std::cout << l << "\n";
    }
}

E. Melody

题意:每个元素有\(a_i, b_i\)。你要构造一个排列,使得任意相邻的两个元素在\(a, b\)中恰好有一个不同,且没有连续的三个元素的\(a\)\(b\)都相同。

\(a_i\)\(b_i\)无向边。那么选择一个元素相当于选择了一条边,然后选择的下一个点必然对应另一个元素的\(a\)\(b\),这样就转化为了欧拉路径问题。注意\(a, b\)要分成两部分,相同的\(a,b\)应该视为不同的点,不然会出现自环然后导致有三个连续相同的点。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::pair<int, int>> a(n);
    std::vector<int> b, c;
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i].first >> a[i].second;
    	b.push_back(a[i].first);
    	c.push_back(a[i].second);
    }

    std::ranges::sort(b);
    b.erase(std::unique(b.begin(), b.end()), b.end());
    int m1 = b.size();
    auto get1 = [&](int x) -> int {
    	return std::ranges::lower_bound(b, x) - b.begin();
    };

    std::ranges::sort(c);
    c.erase(std::unique(c.begin(), c.end()), c.end());
    int m2 = c.size();
    auto get2 = [&](int x) -> int {
    	return std::ranges::lower_bound(c, x) - c.begin();
    };

    int m = m1 + m2;
    std::vector<int> head(m, -1), ver(2 * n), next(2 * n);
    int tot = 0;
    auto add = [&](int u, int v) -> void {
    	ver[tot] = v; next[tot] = head[u]; head[u] = tot ++ ;
    };


    std::vector<int> deg(m);
    for (int i = 0; i < n; ++ i) {
    	auto & [u, v] = a[i];
    	u = get1(u);
    	v = get2(v) + m1;
    	add(u, v);
    	add(v, u);
    	++ deg[u]; ++ deg[v];
    }
    int odd = 0, s = -1;
    for (int i = 0; i < m; ++ i) {
    	if (deg[i] & 1) {
    		++ odd;
    		s = i;
    	}
    }

    if (odd != 0 && odd != 2) {
    	std::cout << "NO\n";
    	return;
    }

    if (s == -1) {
    	s = 0;
    }

    std::vector<int> vis(n * 2);
    std::vector<int> ans;
    auto euler = [&](auto & self, int u) -> void {
    	while (head[u] != -1) {
    		int i = head[u];
    		while (i != -1 && vis[i]) {
    			i = next[i];
    		}

    		if (i == -1) {
    			break;
    		}

			vis[i] = vis[i ^ 1] = 1;
			head[u] = next[i];
			self(self, ver[i]);
			ans.push_back(i / 2);
    	}
    };

    euler(euler, s);
    if (ans.size() != n) {
    	std::cout << "NO\n";
    	return;
    }
    std::cout << "YES\n";
    for (int i = 0; i < n; ++ i) {
    	std::cout << ans[i] + 1 << " \n"[i == n - 1];
    }
}
posted @ 2025-05-25 00:47  maburb  阅读(686)  评论(2)    收藏  举报