The 3rd Universal Cup. Stage 14: Harbin

C. Giving Directions in Harbin

一个简单的模拟题,主要是处理好转向。

#include <bits/stdc++.h>

#define ll long long

using namespace std;

vector<string> dir = {"N", "E", "S", "W"};


void solve(){
	int n;
	cin >> n;
	vector<pair<string,int>> op(n);
	for(auto &[d, x] : op)
		cin >> d >> x;

	vector<string> res;
	string staD = op[0].first;

	int t = 0;
	if(staD == "E") t = 1;
	else if(staD == "S") t = 2;
	else if(staD == "W") t = 3;

	for(auto [d, x] : op) {
		if(dir[t] != d) {
			int t1 = (t + 1) % 4; 
			int t2 = (t + 3) % 4;
			if(dir[t1] == d) res.push_back("R"), t = t1;
			else if(dir[t2] == d) res.push_back("L"), t = t2;
		}
		res.push_back("Z " + to_string(x));
	}
	cout << res.size() << " " << staD << "\n";
	for(auto i : res)
		cout << i << "\n";
	return;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int T;
	cin >> T;

	while(T --)
		solve();

	return 0;
}

G. Welcome to Join the Online Meeting!

我们称不能拉人的为特殊点。

我们记无向图的的时候本质是对每一条边记两条有向边。我们把图中所有以特殊点为起点的边删掉。

找到任意一个非特殊点的点作为起点,从这个点开始进行 bfs,检查能否遍历完整张图,并记录每个点是被哪个点遍历到的。

#include <bits/stdc++.h>

#define ll long long

using namespace std;

using vi = vector<int>;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, m, k;
	cin >> n >> m >> k;

	vi cannot(n + 1);
	for(int i = 0, x; i < k; i ++) {
		cin >> x;
		cannot[x] = 1;
	}

	vector<vi> g(n + 1);
	for(int u, v; m; m --) {
		cin >> u >> v;
		if(cannot[u] and cannot[v]) continue;

		if(cannot[u]) {
			g[v].push_back(u);
		} else if(cannot[v]) {
			g[u].push_back(v);
		} else {
			g[u].push_back(v), g[v].push_back(u);
		}
	}

	int root = -1;
	for(int i = 1; i <= n; i ++) {
		if(cannot[i]) continue;
		root = i;
		break;
	}

	if(root == -1) {
		cout << "No\n";
		return 0;
	}
	queue<int> que;
	vector<pair<int,vi>> res;
	vi vis(n + 1);
	que.push(root), vis[root] = 1;
	while(not que.empty()) {
		int x = que.front();
		que.pop();
		vi nxt;
		for(auto y : g[x]) {
			if(vis[y]) continue;
			que.push(y), vis[y] = 1;
			nxt.push_back(y);
		}
		if(nxt.empty()) continue;
		res.emplace_back(x, nxt);
	}

	for(int i = 1; i <= n; i ++) {
		if(vis[i]) continue;
		cout << "No\n";
		return 0;
	}

	cout << "Yes\n" << res.size() << "\n";
	for(auto [x, nxt] : res) {
		cout << x << " " << nxt.size();
		for(auto i : nxt) cout << " " << i;
			cout << "\n";
	}
	return 0;
}

J. New Energy Vehicle

一个比较显然的思路是,对于电池的使用,我们优先选择充电站近的电池。因此我们可以用优先队列维护选择电池的策略。

为什么这么做复杂度没有问题?如果每次电池用的很少,则自然是\(O(1)\) 的,如果我某一次电池使用的很多,比如达到了\(O(n)\)的级别,哪么之后的每次至多只能使用一个电池。

因此我认为,复杂度最高的情况是,每次都使用\(O(\sqrt n)\)块电池。因此这样的话,复杂度是\(O(n \sqrt n \log n)\)

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;
using pii = pair<int,int>;

const int inf = LLONG_MAX / 2;

void solve() {
	int n, m;
	cin >> n >> m;
	vi a(n + 1);
	for(int i = 1; i <= n; i ++) cin >> a[i];

	vi b = a;
	
	vector<pii> charge(m);
	for(auto &[x, t] : charge) cin >> x >> t;

	vi lst(n + 1, inf), suf(m + 1);
	
	for(int i = m - 1; i >= 0; i --) {
		auto [pos, ti] = charge[i];
		suf[i] = lst[ti], lst[ti] = i;
	}

	int now = 0;

	priority_queue<pii, vector<pii>, greater<pii>> bank;
	for(int i = 1; i <= n; i ++)
		bank.emplace(lst[i], i);

	for(int i = 0; i < m; i ++) {
		auto[x, t] = charge[i];
		while(now < x and not bank.empty()) {
			auto [it, p] = bank.top();
			bank.pop();
			int y = min(x - now, b[p]);
			now += y, b[p] -= y;
			if(b[p] > 0 and p != t) bank.emplace(it, p);
		}
		if(now == x) {
			b[t] = a[t];
			bank.emplace(suf[i], t);
		}else {
			break;
		}
	}
	for(auto i : b) {
		now += i;
	}
	cout << now << "\n";

}
i32 main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int T;
	cin >> T;
	while(T --)
		solve();
	return 0;
}

K. Farm Management

如果我们消除了某一种农作物的限制,则我们是不会选择比这种农作物更廉价的农作物。

我们选择农作物的时候肯定是优先选择价值更高的农作物,因此我们按照价值排序。

题目保证了$\sum l \le m $,因此对于每一种农作物,我们可以先操作最低限制,这样剩下的额外农作物我们就可以任意操作。

我们从价值低到高枚举消除哪一种农作物的限制。对于当前农作物,我们首先舍弃掉最低限制,把多余的时间都用来贪心的选择高价价值的农作物,如果所有高价值农作物都选满之后依旧有空余的时间,我们则可以用当前的农作物填满。

#include <bits/stdc++.h>

using namespace std;

using i32 = int32_t;
using i64 = long long;

#define int i64

using vi = vector<int>;

i32 main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int n, m;
	cin >> n >> m;
	vector<array<int,3>> c(n + 1);

	for(int i = 1; i <= n; i ++) {
		 int w, l, r;
		 cin >> w >> l >> r;
		 c[i] = {w, l, r - l};
	}

	ranges::sort(c);

	int sum = 0, used = 0;
	for(int i = 1; i <= n; i ++) {
		auto [wi, li, ri] = c[i];
		sum += li * wi, used += li;
	}

	vi suf(n + 2), suf_used(n + 2);
	for(int i = n; i >= 1; i --) {
		suf[i] = suf[i + 1] + c[i][0] * c[i][2];
		suf_used[i] = suf_used[i + 1] + c[i][2];
	}

	int res = 0;
	for(int i = 1; i <= n; i ++) {
		int now_sum = sum - c[i][1] * c[i][0];
		int now_can = m - (used - c[i][1]);
		int l = i + 1, r = n + 1, it = -1;
		while(l <= r) {
			int mid = (l + r) / 2;
			if(suf_used[mid] <= now_can) it = mid, r = mid - 1;
			else l = mid + 1;
		}

		now_sum += suf[it];
		now_can -= suf_used[it];
		it --;
		now_sum += now_can * c[it][0];
		res = max(res, now_sum);
	}
	cout << res;
	return 0;
}

M. Weird Ceiling

结果一定是因数,我们求出因数后,计算出每个因数的贡献。

#include <bits/stdc++.h>

#define ll long long

using namespace std;


void solve(){
	int n;
	cin >> n;
	vector<ll> div;
	for(ll i = 1; i * i <= n; i ++) {
		if(n % i == 0) {
			div.push_back(i);
			div.push_back(n / i);
		}
	}
	sort(div.begin(), div.end());
	ll ans = 0;

	for(int i = 0; i < div.size() - 1; i ++) {
		ans += 1ll * n / div[i] * (div[i + 1] - div[i]);
	}
	cout << ans + 1 << "\n";
	return;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);

	int T;
	cin >> T;

	while(T --)
		solve();

	return 0;
}
posted @ 2024-11-03 18:38  PHarr  阅读(46)  评论(0编辑  收藏  举报