2024 睿抗機器人開發者大賽CAIP-程式設計技能賽-本科組(國賽)

Ke_scholar發表於2024-08-05

2024 睿抗機器人開發者大賽CAIP-程式設計技能賽-本科組(國賽)

前言

補題只補了前四道,第五題打個暴力都有 \(24\) 分,我這死活只有 \(22\)\(QAQ\)

RC-u1 大家一起查作弊

思路

按題意模擬。

不過很奇怪賽時用 getline 老是讀入不了,還好換成 cin 直接讀也問題不大。

程式碼

#include <bits/stdc++.h>

using namespace std;

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

	auto check0 = [](char c)->bool{
		bool res = 0;
		if (c >= '0' && c <= '9') res = 1;
		if (c >= 'a' && c <= 'z') res = 1;
		if (c >= 'A' && c <= 'Z') res = 1;
		return res;
	};

	auto check1 = [](string s)->int{
		int res = 0;
		for (int i = 0; i < s.size(); i ++) {
			if (s[i] >= '0' && s[i] <= '9')
				res ++;
		}
		return res;
	};

	auto check2 = [](string s)->int{
		int res = 0;
		for (int i = 0; i < s.size(); i ++) {
			if (s[i] >= 'a' && s[i] <= 'z')
				res ++;
		}
		return res;
	};

	auto check3 = [](string s)->int{
		int res = 0;
		for (int i = 0; i < s.size(); i ++) {
			if (s[i] >= 'A' && s[i] <= 'Z')
				res ++;
		}
		return res;
	};

	vector<string> a;
	string s;
	while (cin >> s) {
		for (int i = 0; i < s.size(); i ++) {
			if (check0(s[i])) {
				int j = i + 1;
				while (j < s.size() && check0(s[j])) {
					j ++;
				}
				a.emplace_back(s.substr(i, j - i));
				i = j;
			}
		}
	}

	int ans1 = 0, ans2 = 0;
	for (auto s : a) {
		ans2 += s.size();
		int x = check1(s), y = check2(s), z = check3(s);
		if (x && y && z) ans1 += 5;
		else if (x && (y || z)) ans1 += 3;
		else if (y && z) ans1 += 1;
	}

	cout << ans1 << '\n' << ans2 << ' ' << a.size() << '\n';

	return 0;
}

RC-u2 誰進線下了?II

思路

按題意模擬,注意不要輸出未參賽的隊伍分數。

程式碼

#include <bits/stdc++.h>

using namespace std;

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

	auto get = [](int x)->int{
		if (x == 1) return 25;
		if (x == 2) return 21;
		if (x == 3) return 18;
		return 20 - x;
	};

	int n;
	cin >> n;

	vector<array<int, 2>> a(31);

	for (int i = 1; i <= 30; i ++) {
		a[i][1] = i;
	}

	set<int> ok;
	while (n--) {
		for (int i = 1; i <= 20; i ++) {
			int c, p;
			cin >> c >> p;
			a[c][0] += get(p);
			ok.insert(c);
		}
	}

	sort(a.begin() + 1, a.end(), [](auto x, auto y) {
		if (x[0] == y[0]) return x[1] < y[1];
		return x[0] > y[0];
	});

	for (int i = 1; i <= 30; i ++) {
		if (ok.count(a[i][1])) {
			cout << a[i][1] << ' ' << a[i][0] << '\n';
		}
	}

	return 0;
}

RC-u3 勢均力敵

思路

賽後聽佬們說有規律,不過我是蠢比找不出規律,只好寫暴力了 \(\dots\)

考慮到 \(4!=24\),直接暴力搜尋有 \(2^{24}\) 會超時,那就雙向搜尋好了,要找兩個集合,使其平方和相等, 列舉一半 \(2^{12}\) 找到兩個集合各一半的和假設為 \([a,b]\),再列舉另一半找到的和假設為 \([c,d]\),那麼有 \(a+c=b+d\),即 \(a-b=c-d\),所以我們只要存下差值即可,然後還要存下兩個集合中選的數有沒有一半,這裡我是直接判斷狀態中 \(1\) 的個數有沒有一半,找到了就直接輸出。

程式碼

#include <bits/stdc++.h>

using i64 = long long;

using namespace std;

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

	int n;
	cin >> n;

	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++)
		cin >> a[i];

	vector<int> num;
	int vis[5] {};
	auto dfs = [&](auto & self, int x, int res)->void{
		if (x == n) {
			num.emplace_back(res);
			return ;
		}

		for (int i = 1; i <= n; i ++) {
			if (!vis[i]) {
				vis[i] = 1;
				self(self, x + 1, res * 10 + a[i]);
				vis[i] = 0;
			}
		}
	};

	dfs(dfs, 0, 0);

	int y = 1;
	for (int i = 1; i <= n; i ++)
		y *= i;

	y /= 2;

	auto print = [&](int a, int b)->void{
		for (int i = 0; i < y; i ++) {
			if (a >> i & 1) {
				cout << num[i] << '\n';
			}
		}
		for (int i = 0; i < y; i ++) {
			if (b >> i & 1) {
				cout << num[i + y] << '\n';
			}
		}
	};

	map<i64, vector<int>> mp;
	for (int i = 1; i < (1 << y); i ++) {
		i64 f = 0, res1 = 0, res0 = 0;
		for (int j = 0; j < y; j ++) {
			if (i >> j & 1) {
				res1 += num[j] * num[j];
			} else {
				res0 += num[j] * num[j];
			}
		}
		mp[res1 - res0].push_back(i);
	}

	for (int i = 1; i < (1 << y); i ++) {
		i64 f = 0, res1 = 0, res0 = 0;
		for (int j = 0; j < y; j ++) {
			if (i >> j & 1) {
				res1 += num[j + y] * num[j + y];
			} else {
				res0 += num[j + y] * num[j + y];
			}
		}
		if (mp.count(res0 - res1)) {
			for (auto st : mp[res0 - res1]) {
				if (__builtin_popcount(i) + __builtin_popcount(st) == y) {
					print(st, i);
					return 0;
				}
			}
		}
	}

	return 0;
}

RC-u4 City 不 City

思路

賽中只拿了 20 分,後來沒時間 debug 了,賽後來改了幾行就過了 \(\dots\)

很一眼的 \(dijkstra\),但是需要維護路徑上的最高熱度值,所以新增一個 \(path\) 陣列維護路徑上除起點和終點以外的最大熱度值最小即可。

程式碼

#include <bits/stdc++.h>

using i64 = long long;

using namespace std;

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

	int n, m, s, t;
	cin >> n >> m >> s >> t;

	vector<int> a(n + 1);
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}

	vector<vector<pair<int, int>>> g(n + 1);
	for (int i = 0; i < m; i ++) {
		int u, v, w;
		cin >> u >> v >> w;
		g[u].push_back({v, w});
		g[v].push_back({u, w});
	}

	vector<int> dis(n + 1, 1e9), path(n + 1);
	priority_queue<array<int, 2>> Q;

	dis[s] = 0;
	Q.push({0, s});
	while (Q.size()) {
		auto [d, u] = Q.top();
		Q.pop();


		if (dis[u] < d) continue;

		for (auto [v, w] : g[u]) {
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				Q.push({ -dis[v], v});
				if (v != t) {
					path[v] = max(path[u], a[v]);
				} else {
					path[v] = path[u];
				}
			} else if (dis[v] == dis[u] + w) {
				path[v] = min(max(a[v], path[u]), path[v]);
			}
		}
	}

	if (dis[t] == 1e9) {
		cout << "Impossible\n";
	} else {
		cout << dis[t] << ' ' << path[t] << '\n';
	}

	return 0;
}

RC-u5 貪心消消樂

思路

唉不太會,聽別人說寫個二維字首和暴力都能有 \(24\) 分來著,我後來改了好久也只會 \(22\) 分的,等之後改完了再重新更新下吧。

大概思路就是, \(n^3\) 的字首和掃描每行的最大子段和 \(dp\),會 wa 第二個和最後一個點,想不明白。

哦對了,這個傻逼題還把行和列反著給,一個樣例給我硬控幾分鐘,wok。

程式碼

#include <bits/stdc++.h>

using i64 = long long;

using namespace std;

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

	int n;
	cin >> n;

	const int inf = -5e5;

	vector a(n + 1, vector<int>(n + 1));
	for (int i = 1; i <= n; i ++) {
		for (int j = 1; j <= n; j ++) {
			cin >> a[j][i];
			if (!a[j][i])
				a[j][i] = inf;
		}
	}

	auto Min = [](array<int, 5> &x, array<int, 5> &y)->array<int, 5> {
		if (x[0] != y[0])
			return x[0] > y[0] ? x : y;
		if (x[1] != y[1])
			return x[1] < y[1] ? x : y;
		if (x[2] != y[2])
			return x[2] < y[2] ? x : y;
		if (x[3] != y[3])
			return x[3] < y[3] ? x : y;
		return x[4] < y[4] ? x : y;
	};

	int ans = 0;
	while (true) {
		// for (int i = 1; i <= n; i ++)
		// 	for (int j = 1; j <= n; j ++)
		// 		cout << a[i][j] << " \n"[j == n];
		array<int, 5> res{inf, 0, 0, 0, 0};
		for (int i = 1; i <= n; i ++) {
			vector<int> pre(n + 1);
			for (int j = i; j <= n; j ++) {
				vector<array<int, 2>> dp(n + 1);
				// cout << i << ' ' << j << ":\n";
				for (int k = 1; k <= n; k ++) {
					pre[k] += a[j][k];
					// cout << pre[k] << " \n"[k == n];
				}
				for (int k = 1; k <= n; k ++) {
					dp[k][1] = k;
					if (k > 1 && dp[k - 1][0] + pre[k] > dp[k][0]) {
						dp[k] = dp[k - 1];
					}
					dp[k][0] += pre[k];
					array<int, 5> t = {dp[k][0], i, dp[k][1], j, k};
					res = Min(res, t);
				}
			}
		}

		if (res[0] <= 0) {
			break;
		}

		ans += res[0];
		auto [v, x1, y1, x2, y2] = res;
		cout << '(' << x1 << ", " << y1 << ") (" << x2 << ", " << y2 << ") " << v << '\n';

		int len = y2 - y1 + 1, no = -1e5;
		for (int i = x1; i <= x2; i ++) {
			for (int j = y1; j <= y2; j ++) {
				a[i][j] = no;
			}
			for (int j = n; j >= 1; j --) {
				if (a[i][j] != no) {
					int k = j;
					while (k + 1 <= n && a[i][k + 1] == no) {
						swap(a[i][k], a[i][k + 1]);
						k ++;
					}
				}
			}
			for (int j = 1; j <= n; j ++) {
				if (!a[i][j]) {
					a[i][j] = inf;
				}
			}
		}
	}

	cout << ans << '\n';

	return 0;
}

相關文章