VP Educational Codeforces Round 27


A. Chess Tourney

题意:把一个数组分成两组,使得一个数组的每一个数都的大于另一个数组的每一个数。

排序后判断中间两个数是不是相等。

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

    std::sort(a.begin(), a.end());
    if (a[n / 2] > a[n / 2 - 1]) {
    	std::cout << "YES\n";
    } else {
    	std::cout << "NO\n";
    }
}

B. Luba And The Ticket

题意:给你一个数字串,使得前三个数的和等于后三个数的和,求更改的数最小。

枚举每个数的取值。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    int ans = 1e9;
    for (int i = 0; i <= 9; ++ i) {
    	for (int j = 0; j <= 9; ++ j) {
    		for (int k = 0; k <= 9; ++ k) {
    			for (int x = 0; x <= 9; ++ x) {
    				for (int y = 0; y <= 9; ++ y) {
    					for (int z = 0; z <= 9; ++ z) {
    						if (i + j + k == x + y + z) {
    							ans = std::min(ans, (s[0] - '0' != i) + (s[1] - '0' != j) + (s[2] - '0' != k)
    								+ (s[3] - '0' != x) + (s[4] - '0' != y) + (s[5] - '0' != z));
    						}
    					}
    				}
    			}
    		}
    	}
    }

    std::cout << ans << "\n";
}

C. Two TVs

题意:若干个区间分成两组,每一组的区间都没有交集。

按右端点排序,维护两组的最大右端点,每次新加进来的区间放到右端点最小的组。

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

    std::sort(a.begin(), a.end());
    int r1 = -1, r2 = -1;
    for (auto & [r, l] : a) {
    	if (r1 < r2) {
    		std::swap(r1, r2);
    	}
    	if (l > r1) {
    		r1 = r;
     	} else if (l > r2) {
     		r2 = r;
     	} else {
     		std::cout << "NO\n";
     		return;
     	}
    }

    std::cout << "YES\n";
}

D. Driving Test

题意很长,懒得说了。

模拟题。
维护超车不合法的贡献就是记录出现过的不让超车的次数。每次超车就加上这个次数,然后次数清零。遇到可以超车的标记也清零。
然后对于超速的处理,把每个速度限制加到栈里,每次把栈里小于车速的弹出来并计算贡献。遇到无限制标志就把栈情况。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    const int inf = 1e9;
    int limit = inf, speed = 0;
    bool flag = true;
    int flag_cnt = 0;
    std::stack<int> stk;
    int ans = 0;
    while (n -- ) {
    	int t, s;
    	std::cin >> t;
    	if (t == 1) {
    		std::cin >> s;
    		speed = s;
			while (stk.size() && stk.top() < speed) {
				++ ans;
				stk.pop();
			}

    	} else if (t == 2) {
    		if (!flag) {
    			ans += flag_cnt;
    			flag_cnt = 0;
    		}
    	} else if (t == 3) {
    		std::cin >> s;
    		limit = s;
			stk.push(limit);

			while (stk.size() && stk.top() < speed) {
				++ ans;
				stk.pop();
			}
    	} else if (t == 4) {
    		flag = true;
			flag_cnt = 0;
    	} else if (t == 5) {
    		limit = inf;
    		while (stk.size()) {
    			stk.pop();
    		}
    	} else {
    		flag = false;
    		flag_cnt += 1;
    	}
    }

    std::cout << ans << "\n";
}

E. Fire in the City

题意:一个\(n \times m\)的矩阵有\(k + 1\)个点,每个点每秒会扩大一倍,覆盖一个\(2 \times t +1\)的矩阵。给出你\(k\)个点,还有一个点不知道,你需要确定整个矩阵被包含的最小时间。

如果已知所有点和时间,那么我们可以离散化加差分处理。把每个点当前的矩阵四个角及其周边的点加进来离散。然后把每个矩阵加一。差分后值是\(0\)的矩阵就没有被覆盖。此时如果想加进来一个点覆盖这些没有被覆盖的点,需要这些点形成的大矩阵能被整个点覆盖,可以直接找到每个边界的点根据距离判断。
那么到这个题,我们可以二分时间,然后就是上述操作去\(check\)

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

    auto check = [&](int t) -> bool {
    	std::vector<int> X, Y;
    	for (auto & [x, y] : a) {
    		int x1 = std::max(1, x - t), x2 = std::min(n, x + t);
    		int y1 = std::max(1, y - t), y2 = std::min(m, y + t);
    		X.push_back(x1);
    		X.push_back(x2);
    		Y.push_back(y1);
    		Y.push_back(y2);
    		if (x1 > 1) {
    			X.push_back(x1 - 1);
    		}

    		if (x2 < n) {
    			X.push_back(x2 + 1);
    		}

    		if (y2 < m) {
    			Y.push_back(y2 + 1);
    		}

    		if (y1 > 1) {
    			Y.push_back(y1 - 1);
    		}
    	}

    	X.push_back(1); X.push_back(n);
    	Y.push_back(1); Y.push_back(m);
    	std::sort(X.begin(), X.end());
    	X.erase(std::unique(X.begin(), X.end()), X.end());
    	std::sort(Y.begin(), Y.end());
    	Y.erase(std::unique(Y.begin(), Y.end()), Y.end());

    	int N = X.size(), M = Y.size();
    	auto getx = [&](int x) -> int {
    		return std::lower_bound(X.begin(), X.end(), x) - X.begin() + 1;
    	};

    	auto gety = [&](int y) -> int {
    		return std::lower_bound(Y.begin(), Y.end(), y) - Y.begin() + 1;
    	};

    	std::vector d(N + 2, std::vector<int>(M + 2));
    	for (auto & [x, y] : a) {
    		int x1 = std::max(1, x - t), x2 = std::min(n, x + t);
    		int y1 = std::max(1, y - t), y2 = std::min(m, y + t);
    		x1 = getx(x1);
    		x2 = getx(x2);
    		y1 = gety(y1);
    		y2 = gety(y2);
    		++ d[x1][y1];
    		-- d[x1][y2 + 1];
    		-- d[x2 + 1][y1];
    		++ d[x2 + 1][y2 + 1];
    	}

    	for (int i = 1; i <= N; ++ i) {
    		for (int j = 1; j <= M; ++ j) {
    			d[i][j] += d[i - 1][j] + d[i][j - 1] - d[i - 1][j - 1];
    		}
    	}

    	int minx = N, maxx = 1, miny = M, maxy = 1;
    	for (int i = 1; i <= N; ++ i) {
    		for (int j = 1; j <= M; ++ j) {
    			if (d[i][j] == 0) {
    				minx = std::min(minx, i);
    				maxx = std::max(maxx, i);
    				miny = std::min(miny, j);
    				maxy = std::max(maxy, j);
    			}
    		}
    	}

    	return std::max(X[maxx - 1] - X[minx - 1], Y[maxy - 1] - Y[miny - 1]) + 1 <= t * 2 + 1;
    };

    int l = 0, r = std::max(n, m);
    while (l < r) {
    	int mid = l + r >> 1;
    	if (check(mid)) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }

    std::cout << l << "\n";
}
posted @ 2025-03-08 19:37  maburb  阅读(17)  评论(0)    收藏  举报