Codeforces Round 997 (Div. 2)

https://codeforces.com/contest/2056

A. Shape Perimeter

题意:有一个边长为 m 的正方形,依次给定 n 个左下角坐标,求最后连接区域的边长。

题解:确定第一个左下角坐标和最后一个的右上角坐标,即可得到长的宽。

void slove() {
	int n, m; cin >> n >> m;
	int x, y; cin >> x >> y;
	n--;
	int fx = x, fy = y;
	while (n --) {
		int a, b; cin >> a >> b;
		x += a, y += b;
	}
	int res = x + m - fx + y + m - fy;
	res *= 2;
	cout << res << endl;
} 

B. Find the Permutation

题意:给定一个邻接矩阵,如果 u 和 v 之间有一条无向边,那么会有排列满足如下规则:\(u<v, p_u < p_v\) . 只要满足这个条件的两个顶点就存在无向边 . 按照给定的邻接矩阵构造排列.

题解: 使用拓扑排序, 如果 u < v 并且存在 (u, v) 的无向边, 那么排列的 u 要在 v 前面, 如果不存在边, v 要在 u 前面. 做一边topo就可以了.

const int N = 1005;
vector<int> g[N];
int n;
vector<int> topo() {
	vector<int> res; 
	queue<int> q;
	vector<int> d(n + 5);
	for (int i = 1; i <= n; i++) {
		for (auto v : g[i]) d[v]++;   
	}
	for (int i = 1; i <= n; i++) {
		if (d[i] == 0) q.push(i);
	}
	while(!q.empty()) {
		int u = q.front(); q.pop();
		res.emplace_back(u);
		for (auto v : g[u]) {
			if (--d[v] == 0) q.push(v);
		}
	}
	return res;
}
void slove() {
	cin >> n;
	vector<string> a(n + 5);
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	for (int i = 1; i <= n; i++) {
		g[i].clear();
	}
	for (int i = 0; i < n; i++) {
		for (int j = i + 1; j < n; j++) {
			int u = i + 1, v = j + 1;
			if (a[i][j] == '0') {
				g[v].emplace_back(u);
			} else {
				g[u].emplace_back(v);
			}
		}
    }
	vector<int> res = topo();
	for (int e : res) {
		cout << e << " ";
	} 
	cout << endl;
} 

C. Palindromic Subsequences

题意: 定义一个序列的最长回文子序列长度为 f(a), g(a) 是 f(a) 的数量. 构造一个 g(a) 大于等于 n 的长度为 n 的序列.

题解: 我们使得构造的序列最长回文子序列长度为 3. [1, 1, 2, ....... , 1, 2] 至少可以构成 n-3 + n-4 + n-4 = 3*n - 11, 已知 n >= 6, 那么 \(3\times n-11>n\)

void slove() {
	int n; cin >> n;
	vector<int> res(n + 5);
	res[1] = res[2] = res[n - 1] = 1;
	res[3] = res[n] = 2;
	for (int i = 4; i <= n - 2; i++) {
		res[i] = i;
	}
	for (int i = 1; i <= n; i++) {
		cout << res[i] << " ";
	}
	cout << endl;
} 

D. Unique Median

题意:给定一个数组,如果一个子数组的中位数相等就是好的,否则就是坏的。计算好的子数组的个数。\(a_i \leq10, n\leq10^5\)

题解:当子数组长度为奇数时,中位数是确定的,一定是好的。如果子数组长度为偶数才存在坏的可能。计算坏的子数组数量。
值域很小,当确定一个长度为偶数的子数组,两个中位数之一为 x,那么所有小于等于 x 的为 -1, 大于 x 的为 1. 当这两种元素的数量相等,即子数组和为 0. 这个时候,x 一定为靠左的中位数,且另一个中位数一定大于 x。所有计算这样的子数组数量即可。

注意,需要这个子数组中存在 x 才可以累加,否则就会重复了。

void slove() {
	int n; cin >> n;
	vector<int> a(n + 5);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	LL sum = 0;
	for (int x = 1; x <= 10; x++) {
		vector<int> pre(n + 5);
		for (int i = 1; i <= n; i++) {
			pre[i] = pre[i - 1] + (a[i] <= x ? -1 : 1);
		}
		vector<int> cnt(2 * n + 5);
		for (int l = 1, r = 1; r <= n; r++) {
			if (a[r] == x) {
				while (l <= r) {
					cnt[pre[l - 1] + n]++;
					l++;
				}
			}
			sum += cnt[pre[r] + n];
		}
		
	}
	cout << 1LL * n * (n + 1) / 2 - sum << endl;
} 
posted @ 2025-10-07 12:56  yairr  阅读(10)  评论(0)    收藏  举报