VP Educational Codeforces Round 38 (Rated for Div. 2)


A. Word Correction

模拟

点击查看代码
void solve() {
	int n;
	std::cin >> n;
    std::string s;
    std::cin >> s;
    std::string ans;
    auto check = [&](char c) -> bool {
    	return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' || c == 'y';
    };

    for (int i = 0; i < n; ++ i) {
    	ans += s[i];
    	int j = i + 1;
    	while (j < n && check(s[i]) && check(s[j])) {
    		++ j;
    	}

    	i = j - 1;
    }

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

B. Run For Your Prize

题意:两个人在数轴的两段,每秒钟走一步,有\(n\)个物品,求拿走全部物品的最短时间。

每个物品被距离最近的人拿走,所有物品被拿走的时间取最大值。

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

    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	ans = std::max(ans, std::min(a[i] - 1, 1000000 - a[i]));
    }

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

C. Constructing Tests

题意:一个\(n\times n\)\(01\)矩阵如果满足任意一个\(m\times m\)的子矩阵都至少有一个\(0\),且\(1\)的数量尽可能多,这个矩阵就满足\((n,m)\)的条件。现在给出\(1\)的数量为\(x\),找\(n, m\)

题目要求我们反向想,但这并不好想,先正着想一个满足\(n, m\)的矩阵有多少个\(1\)。发现一个每隔\(m\)\(m\)列放一个\(0\),手画一下发现总共有\((\lfloor \frac{n}{m} \rfloor)^2\)\(0\),那么总共有\(n^2 - (\lfloor \frac{n}{m} \rfloor)^2\)\(1\)。那么我们就是求\(n^2 - (\lfloor \frac{n}{m} \rfloor)^2 = x\)
那么可以得到\((n + \lfloor \frac{n}{m} \rfloor) \times (n - \lfloor \frac{n}{m} \rfloor) = x\)。那么我们可以枚举\(x\)的因子,然后求出\(n\)\(m\)

点击查看代码
void solve() {
    i64 x;
    std::cin >> x;
    if (x == 0) {
    	std::cout << 1 << " " << 1 << "\n";
    	return;
    }

    if (x == 1) {
    	std::cout << -1 << "\n";
    	return;
    }

    //n * n - (n / m) * (n / m) = x
    //(n + n / m)(n - n / m) = x
    for (i64 i = 1; i * i < x; ++ i) {
    	if (x % i == 0) {
    		i64 a = x / i, b = i;
    		i64 n = (a + b) / 2, m = (a + b) / (a - b);
    		if (n * n - (n / m) * (n / m) == x) {
    			std::cout << n << " " << m << "\n";
    			return;
    		}
    	}
    }

    std::cout << -1 << "\n";
}

D. Buy a Ticket

题意:给你一个图,每个点有点权,每个边有边权。对每个点求一个终点,使得这个点到终点的最短路长度的两倍加终点点权的值最小。

超级源点。
一开始把每个点都入队,值为这个点的点权,然后跑最短路。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    using PII = std::pair<i64, i64>;
    std::vector<std::vector<PII>> adj(n);
    for (int i = 0; i < m; ++ i) {
    	int u, v;
    	i64 w;
    	std::cin >> u >> v >> w;
    	-- u, -- v;
    	adj[u].push_back({v, w * 2});
    	adj[v].push_back({u, w * 2});
    }

    std::vector<i64> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    const i64 inf = 1e18;
    std::priority_queue<PII, std::vector<PII>, std::greater<PII>> heap;
    std::vector<i64> dist(n, inf);
    for (int i = 0; i < n; ++ i) {
    	dist[i] = a[i];
    	heap.emplace(dist[i], i);
    }

    while (heap.size()) {
    	auto [d, u] = heap.top(); heap.pop();
    	if (d != dist[u]) {
    		continue;
    	}

    	for (auto & [v, w] : adj[u]) {
    		if (dist[v] > d + w) {
    			dist[v] = d + w;
    			heap.emplace(dist[v], v);
    		}
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	std::cout << dist[i] << " \n"[i == n - 1];
    }
}
posted @ 2025-03-20 16:34  maburb  阅读(7)  评论(0)    收藏  举报