TOYOTA SYSTEMS Programming Contest 2025(AtCoder Beginner Contest 431)


A - Robot Balance

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int a, b;
	std::cin >> a >> b;
	std::cout << std::max(0, a - b) << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

B - Robot Weight

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int x, n;
	std::cin >> x >> n;
	std::vector<int> a(n), st(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	int q;
	std::cin >> q;
	while (q -- ) {
		int id;
		std::cin >> id;
		-- id;
		if (st[id]) {
			x -= a[id];
		} else {
			x += a[id];
		}

		st[id] ^= 1;
		std::cout << x << "\n";
	}
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

C - Robot Factory

题意:两个数组\(a, b\)。如果\(a_i \leq b_j\)则可以匹配这两个元素。求最多匹配多少对。

两个数组从小到大排序,双指针找一下每个大于等于\(a_i\)\(b_j\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, m, k;
	std::cin >> n >> m >> k;
	std::vector<int> a(n), b(m);
	for (int i = 0; i < n; ++ i) {
		std::cin >> a[i];
	}

	for (int i = 0; i < m; ++ i) {
		std::cin >> b[i];
	}

	std::ranges::sort(a);
	std::ranges::sort(b);

	for (int i = 0, j = 0; i < n && j < m; ++ i) {
		while (j < m && b[j] < a[i]) {
			++ j;
		}

		if (j < m) {
			-- k;
			++ j;
		} else {
			break;
		}
	}

	if (k <= 0) {
		std::cout << "Yes\n";
	} else {
		std::cout << "No\n";
	}
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

D - Robot Customize

题意:\(n\)个零件,每个零件重量为\(w_i\)。如果这个零件加入头部获得\(h_i\)价值,否则加入身体获得\(b_i\)价值。求一种分配方案,满足头部总重量小于等于身体总重量,且总价值最大。\(n \leq 500, w_i \leq 500\)

\(f_{i, j}\)表示前\(i\)个零件身体占\(j\)重量的最大花费。那么枚举这个零件作为头部还是身体进行转移即可。
如果\(\sum_{i=1}^{n} w_i - j \leq j\),则\(ans = \max(ans, f_{n, j})\)

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n;
	std::cin >> n;
	std::vector<int> w(n), h(n), b(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> w[i] >> h[i] >> b[i];
	}

	int m = std::accumulate(w.begin(), w.end(), 0);
	std::vector<i64> f(m + 1);
	int pre = 0;
	for (int i = 0; i < n; ++ i) {
		std::vector<i64> g(m + 1);
		for (int j = 0; j <= pre; ++ j) {
			g[j + w[i]] = std::max(g[j + w[i]], f[j] + b[i]);
			g[j] = std::max(g[j], f[j] + h[i]);
		}

		f = g;
		pre += w[i];
	}

	i64 ans = 0;
	for (int i = (m + 1) / 2; i <= m; ++ i) {
		ans = std::max(ans, f[i]);
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

E - Reflection on Grid

题意:一个\(n\times m\)的矩阵,有两种镜子,每个位置要么是一种镜子要么没镜子。从\((1, 1)\)的左边射进来一束光,你想让其从\((n, m)\)的右边射出。你可以修改一些位置,求最小修改数量。

\(dist[i][j][k]\)表示位置\((i, j)\)射进来一道往\(k\)方向的光的最小修改数。其中\(k \in [0, 3]\)分别代表上右下左四个方向。那么可以讨论是否修改,不同状态会射到不同的格子,\(01bfs\)跑一下即可。

点击查看代码
#include <bits/stdc++.h>

using i64 = long long;

void solve() {
	int n, m;
	std::cin >> n >> m;
	std::vector<std::string> s(n);
	for (int i = 0; i < n; ++ i) {
		std::cin >> s[i];
	}

	constexpr int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
	auto get = [&](int x, int y, char c, int d) -> std::tuple<int, int, int> {
		if (c == 'A') {
			return {x + dx[d], y + dy[d], d};
		}

		if (c == 'B') {
			if (d == 0) {
				return {x, y - 1, 3};
			} else if (d == 1) {
				return {x + 1, y, 2};
			} else if (d == 2) {
				return {x, y + 1, 1};
			} else {
				return {x - 1, y, 0};
			}
		} else {
			if (d == 0) {
				return {x, y + 1, 1};
			} else if (d == 1) {
				return {x - 1, y, 0};
			} else if (d == 2) {
				return {x, y - 1, 3};
			} else {
				return {x + 1, y, 2};
			}
		}
	};

	constexpr int inf = 1e9;
	std::vector dist(n, std::vector(m, std::array<int, 4>{inf, inf, inf, inf}));
	dist[0][0][1] = 0;
	std::deque<std::tuple<int, int, int>> q;
	q.emplace_back(0, 0, 1);
	while (q.size()) {
		auto [x, y, d] = q.front(); q.pop_front();
		for (char c = 'A'; c <= 'C'; ++ c) {
			auto [nx, ny, nd] = get(x, y, c, d);
			int w = c != s[x][y];
			if (nx < 0 || nx >= n || ny < 0 || ny >= m || dist[nx][ny][nd] <= dist[x][y][d] + w) {
				continue;
			}

			dist[nx][ny][nd] = dist[x][y][d] + w;
			if (w) {
				q.emplace_back(nx, ny, nd);
			} else {
				q.emplace_front(nx, ny, nd);
			}
		}
	}

	int ans = inf;
	for (int i = 0; i < 4; ++ i) {
		for (char c = 'A'; c <= 'C'; ++ c) {
			auto [x, y, d] = get(n - 1, m - 1, c, i);
			if (x == n - 1 && y == m) {
				ans = std::min(ans, dist[n - 1][m - 1][i] + (c != s[n - 1][m - 1]));
			}
		}
	}
	std::cout << ans << "\n";
}

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}

F - Almost Sorted 2

题意:一个长度为\(n\)的数组\(a\),你要将其重排,求可以得到多少个不同的数组\(b\),满足\(b_{i+1} \geq b_i - d\)。两个数组不同那么其至少有一个位置不同。

不同的重排可以得到相同的数组,我们先不考虑去重。
我们考虑从小到大加入\(a_i\),那么如果\(a_i\)插入到\(x, y\)两个元素之间,需要满足\(a_i \geq x - d, y \geq a_i - d\)。因为是从小到大加入,那么\(a_i \geq x - d\)一定满足。问题变为\([1, i - 1]\)里有多少\(a_j \geq a_i - d\)。那么可以用一个指针维护最小满足条件的\(j\)。就有\(i - j + 1\)中方案。
现在考虑去重,如果\(x\)\(cnt_x\)个,那么就会产生\(cnt_x!\)个相同的数组。每个元素产生的方案会乘起来,于是需要把它们都除掉。
代码省略取模类。

点击查看代码
constexpr int P = 998244353;
using Z = MInt<P>;

struct Comb {
    int n;
    std::vector<Z> _fac;
    std::vector<Z> _invfac;
    std::vector<Z> _inv;
    
    Comb() : n{0}, _fac{1}, _invfac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    
    void init(int m) {
        if (m <= n) return;
        _fac.resize(m + 1);
        _invfac.resize(m + 1);
        _inv.resize(m + 1);
        
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _invfac[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _invfac[i - 1] = _invfac[i] * i;
            _inv[i] = _invfac[i] * _fac[i - 1];
        }
        n = m;
    }
    
    Z fac(int m) {
        if (m > n) init(2 * m);
        return _fac[m];
    }
    Z invfac(int m) {
        if (m > n) init(2 * m);
        return _invfac[m];
    }
    Z inv(int m) {
        if (m > n) init(2 * m);
        return _inv[m];
    }
    Z binom(int n, int m) {
        if (n < m || m < 0) return 0;
        return fac(n) * invfac(m) * invfac(n - m);
    }
} comb;

constexpr int N = 1e6;

int sum[N + 1];

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

	std::ranges::sort(a);

	Z ans = 1;
	for (int i = 0, j = 0; i < n; ++ i) {
		while (j < i && a[i] - a[j] > d) {
			++ j;
		}

		ans *= i - j + 1;
	}

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

		ans /= comb.fac(j - i + 1);
		i = j;
	}


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

int main() {
	std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
	int t = 1;
	// std::cin >> t;
	while (t -- ) {
		solve();
	}
	return 0;
}
posted @ 2025-11-08 22:09  maburb  阅读(87)  评论(0)    收藏  举报