Rayan Programming Contest 2024 - Selection (Codeforces Round 989, Div. 1 + Div. 2) 题解 (A~E)

A. King Keykhosrow's Mystery

上限是 \(lcm(a, b)\),直接枚举即可

#include <bits/stdc++.h>

void solve()
{
	int a, b; std::cin >> a >> b;

	int l = std::lcm(a, b);
	for(int i = std::min(a, b); i <= l; i++)
	{
		if(i % a == i % b)
		{
			std::cout << i << "\n";
			return;
		}
	}
}

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

	int t; std::cin >> t;
	while(t--) solve();

	return 0;
}

B. Rakhsh's Revival

贪心,每次 \(0\) 的数量够 \(m\) 个了就往后跳 \(k\)

#include <bits/stdc++.h>

void solve()
{
	int n, m, k; std::cin >> n >> m >> k;
	std::string s; std::cin >> s;

	int cnt = 0, ans = 0;
	for(int i = 0; i < n; i++)
	{
		if(s[i] == '0') cnt++;
		if(s[i] == '1') cnt = 0;

		if(cnt == m) 
		{
			i = std::min(n, i + k - 1);
			cnt = 0;
			ans++;
		}
	}

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

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

	int t; std::cin >> t;
	while(t--) solve();

	return 0;
}

C. Trapped in the Witch's Labyrinth

整个网络可以看成一个有向图,超出网络视为终点,按照给出的字母连反边,从终点开始搜索,路上经过的点代表着最后都会走出这张图,所以不能成为答案,标记一下。处理完这些之后,再处理问号,对于一个问号,如果它上下左右的点都被标记了,说明它最后也会走出去,也不能成为答案。把这些点抛去之后的点就是答案。

#include <bits/stdc++.h>

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];

	std::vector<std::vector<int>> adj(n * m + 1);
	int ed = n * m;
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < m; j++)
		{
			int x = i + (s[i][j] == 'D') - (s[i][j] == 'U');
			int y = j + (s[i][j] == 'R') - (s[i][j] == 'L');
			if(x >= n || y >= m || x < 0 || y < 0) adj[ed].emplace_back(i * m + j);
			else adj[x * m + y].emplace_back(i * m + j);
		}
	}

	std::vector<int> vis(n * m);
	int ans = n * m, st = n * m;
	std::queue<int> q;
	q.emplace(st);
	while(!q.empty())
	{
		int x = q.front(); q.pop();
		for(auto y : adj[x])
		{
			vis[y] = 1;
			ans--;
			q.emplace(y);
		}
	}
	
	std::array<int, 4> dx{0, -1, 0, 1}, dy{-1, 0, 1, 0};
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < m; j++) if(s[i][j] == '?')
		{
			int cnt = 0;
			for(int dir = 0; dir < 4; dir++)
			{
				int x = i + dx[dir], y = j + dy[dir];
				if(x >= n || y >= m || x < 0 || y < 0 || vis[x * m + y]) cnt++;
			}
			if(cnt == 4) ans--;
		}
	}

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

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

	int t; std::cin >> t;
	while(t--) solve();

	return 0;
}

D. Darius' Wisdom

不妨倒着考虑每一位会是什么。可以先用三个 \(set\) 把数字的下标都存下来,然后倒着考虑,先放 \(2\),再放 \(1\),最后是 \(0\)

对于一个位置,如果它应该是 \(2\),但是这里填的是 \(0\),那么我们需要两次交换,这也是交换次数最多的交换。所以极限情况就是构造形如 \(222...21000...0\) 的序列,这种情况我们的总交换次数也不会超过 \(n\),所以就这么交换就好。注意每次我们会选最前面的数交换,因为越小的数最后的位置肯定越靠前,所以早点让它去前面是不劣的。

#include <bits/stdc++.h>

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

	std::array<std::set<int>, 3> pos;
	for(int i = 0; i < n; i++) pos[a[i]].emplace(i);

	std::vector<std::pair<int, int>> ans;
	auto modify = [&](int idx) -> void
	{
		if(!pos[2].empty())
		{
			if(a[idx] == 2) pos[2].erase(idx);
			else if(a[idx] == 1)
			{
				int tmp = *pos[2].begin();
				std::swap(a[idx], a[tmp]);
				pos[2].erase(tmp);
				pos[1].erase(idx);
				pos[1].emplace(tmp);
				ans.emplace_back(idx, tmp);
			}
			else
			{
				int tmp1 = *pos[1].begin(), tmp2 = *pos[2].begin();
				std::swap(a[idx], a[tmp1]);
				std::swap(a[idx], a[tmp2]);
				pos[2].erase(tmp2);
				pos[1].erase(tmp1);
				pos[1].emplace(tmp2);
				pos[0].erase(idx);
				pos[0].emplace(tmp1);
				ans.emplace_back(idx, tmp1);
				ans.emplace_back(idx, tmp2);
			}
		}
		else
		{
			if(a[idx] == 1) pos[1].erase(idx);
			else
			{
				int tmp = *pos[1].begin();
				std::swap(a[idx], a[tmp]);
				pos[1].erase(tmp);
				pos[0].erase(idx);
				pos[0].emplace(tmp);
				ans.emplace_back(idx, tmp);
			}
		}
	};

	for(int i = n - 1; i >= 0; i--)
	{
		if(pos[1].empty() && pos[2].empty()) break;
		modify(i);
	}	
	
	std::cout << ans.size() << "\n";
	for(auto [x, y] : ans) 
		std::cout << x + 1 << " " << y + 1 << "\n";
} 

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

	int t; std::cin >> t;
	while(t--) solve();

	return 0;
}

E. Permutations Harmony

首先可以把 \(n!<k\) 的情况判掉。

然后注意到 \(k\) 如果是偶数是一定可以的,因为我们可以构造 \(\frac{k}{2}\)\({(a_i,n+1-a_i)}\) 排列。

接下来考虑 \(k\) 是奇数的情况:

首先如果 \(k=1\)\(k=n!-1\) 是不行的,因为没的补齐。

我们可以算出来每一列的和是多少,是 \(\frac{n(n+1)}{2} \cdot k \cdot \frac{1}{n}=\frac{(n+1)k}{2}\),所以 \(n\) 此时必须是奇数。实际上我们只需要考虑 \(k=3\),构造出来之后就变成了 \(k\) 是偶数的情况。

考虑 \(n=7\) 的情况,每一列的和最后是 \(12\),先构造 \(7,6,5,4,3,2,1\),剩下需要的和为 \(\{5,6,7,8,9,10,11\}\),注意到我们可以构造 \(\{4,3,2,1,7,6,5\}\),剩下的序列为 \(\{1,3,5,7,2,4,6\}\),刚好满足条件。对于其它 \(n\) 也是这样。

#include <bits/stdc++.h>

using i64 = long long;

void solve()
{
	int n, k; std::cin >> n >> k;

	i64 fac = 1;
	for(int i = 1; i <= n && fac < k + 10; i++) 
		fac *= i;

	if(fac < k)
	{
		std::cout << "NO\n";
		return;
	}

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

	if(k % 2 == 0)
	{
		std::cout << "YES\n";
		std::vector<int> a(n);
		std::iota(a.begin(), a.end(), 1);
		for(int i = 0; 2 * i < k; i++)
		{
			for(int j = 0; j < n; j++) std::cout << a[j] << " \n"[j == n - 1];
			for(int j = 0; j < n; j++) std::cout << n + 1 - a[j] << " \n"[j == n - 1];
			std::next_permutation(a.begin(), a.end());
		}
		return;
	}

	if(k == 1 || k == fac - 1)
	{
		std::cout << "NO\n";
		return;
	}

	if((n + 1) % 2)
	{
		std::cout << "NO\n";
		return;
	}
	
	std::cout << "YES\n";
	std::vector<int> a(n);
	for(int i = 0; i < n; i++) a[i] = i + 1;

	std::set<std::vector<int>> vis;
	for(int i = 0; i < n; i++) a[i] = (n + 1) * 3 / 2 - a[i];
	std::ranges::reverse(a);
	
	std::vector<int> b(n);
	for(int i = a[0] - 1, j = 0; i; i--, j++) b[j] = i;
	for(int i = n, j = a[0] - 1; j < n; i--, j++) b[j] = i;
	vis.emplace(b);

	for(int i = 0; i < n; i++) b[i] = a[i] - b[i];
	vis.emplace(b);

	for(int i = 0; i < n; i++) b[i] = i + 1;
	std::ranges::reverse(b);
	vis.emplace(b);
	std::ranges::reverse(b);
	
	auto ans = vis;
	while(ans.size() < k)
	{
		std::vector<int> c(b);
		for(int j = 0; j < n; j++) c[j] = n + 1 - c[j];
		if(!vis.contains(b) && !vis.contains(c)) 
		{
			ans.emplace(b);
			ans.emplace(c);
		}
		std::next_permutation(b.begin(), b.end());
	}

	for(auto p : ans) for(int i = 0; i < n; i++) std::cout << p[i] << " \n"[i == n - 1];
} 

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

	int t; std::cin >> t;
	while(t--) solve();

	return 0;
}
posted @ 2024-12-01 03:35  Repeater11  阅读(51)  评论(0编辑  收藏  举报