当前位置: 首页 > news >正文

ABC391题解

A

算法标签: 模拟

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>

using namespace std;

const int N = 8;
map<string, string> mp;

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

	mp.insert({"N", "S"});
	mp.insert({"S", "N"});
	mp.insert({"E", "W"});
	mp.insert({"W", "E"});

	mp.insert({"NE", "SW"});
	mp.insert({"SW", "NE"});
	mp.insert({"NW", "SE"});
	mp.insert({"SE", "NW"});

	string s;
	cin >> s;
	cout << mp[s] << "\n";

	return 0;
}

B

算法标签: 模拟

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 60;

int n, m;
char w1[N][N], w2[N][N];

bool check(int x, int y) {
	for (int i = 0; i < m; ++i) {
		for (int j = 0; j < m; ++j) {
			if (w1[i + x][j + y] != w2[i][j]) return false;
		}
	}
	return true;
}

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

	cin >> n >> m;
	for (int i = 0; i < n; ++i) cin >> w1[i];
	for (int i = 0; i < m; ++i) cin >> w2[i];

	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < n; ++j) {
			if (check(i, j)) {
				cout << i + 1 << " " << j + 1 << "\n";
				return 0;
			}
		}
	}

	return 0;
}

C

算法标签: 模拟

在这里插入图片描述

思路

鸽子数量 1 0 6 10 ^ 6 106, 需要线性做法, 开两个数组记录每个鸽子属于哪个巢穴, 以及记录每个巢穴的鸽子数量

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 1e6 + 10;

int n, m;
int fa[N], cnt[N];

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

	cin >> n >> m;
	for (int i = 1; i <= n; ++i) fa[i] = i, cnt[i] = 1;

	int curr = 0;
	while (m--) {
		int op;
		cin >> op;
		if (op == 1) {
			int val, target;
			cin >> val >> target;
			int pos = fa[val];
			
			if (cnt[pos] == 2) curr--;
			cnt[pos]--;
			
			if (cnt[target] == 1) curr++;
			cnt[target]++;
			fa[val] = target;
		}
		else cout << curr << "\n";
	}

	return 0;
}

D

算法标签: 离线做法

在这里插入图片描述
在这里插入图片描述

思路

因为数据范围很大, 方块的数量是 1 0 5 10 ^ 5 105量级, 判断 t t t时刻某个方块是否存在, 将询问时间从小到大排序, 就可以边询问边处理, 这样就能降低复杂度到 O ( T ) O(T) O(T)

具体做法就是, 首先将所有能下落的方块进行下落, 然后判断是否能消除

#include <iostream>
#include <algorithm>
#include <vector>
#include <deque>

using namespace std;

typedef pair<int, int> PII;
const int N = 2e5 + 10;

int n, w, q;
// ((Y, X), 方块id)
pair<PII, int> block[N];
// ((查询时间T, 方块编号A), 查询id)
pair<PII, int> qs[N];
bool ans[N], alive[N];
deque<int> wait_to_del[N];
// 记录有多少列有方块等待被删除
int cnt = 0;

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

	cin >> n >> w;
	for (int i = 1; i <= n; ++i) {
		cin >> block[i].first.second >> block[i].first.first;
		block[i].second = i;
		alive[i] = true;
	}

	cin >> q;
	for (int i = 1; i <= q; ++i) {
		cin >> qs[i].first.first >> qs[i].first.second;
		qs[i].second = i;
	}

	// 将方块按Y坐标升序排序,查询按时间升序排序
	sort(block + 1, block + n + 1);
	sort(qs + 1, qs + q + 1);

	// 当前处理的方块指针
	int curr = 1;
	for (int i = 1; i <= q; ++i) {
		int t = qs[i].first.first;
		int a_id = qs[i].first.second;
		int q_id = qs[i].second;

		// 处理所有在时间t之前应该下落到底部的方块
		while (curr <= n && block[curr].first.first <= t) {
			int col = block[curr].first.second;
			int id = block[curr].second;
			if (wait_to_del[col].empty()) ++cnt;
			wait_to_del[col].push_back(id);
			curr++;
		}

		// 检查是否最底行已满(所有列都有方块等待删除)
		while (cnt == w) {
			for (int j = 1; j <= w; ++j) {
				// 删除该列最下面的方块
				alive[wait_to_del[j].front()] = false;
				wait_to_del[j].pop_front();
				if (wait_to_del[j].empty()) --cnt;
			}
		}

		// 记录当前查询的答案
		ans[q_id] = alive[a_id];
	}

	// 输出所有查询结果
	for (int i = 1; i <= q; ++i) {
		cout << (ans[i] ? "Yes" : "No") << "\n";
	}

	return 0;
}

E

算法标签: 递推, 动态规划, 三叉树, 树形 d p dp dp

在这里插入图片描述
每个三元组输出保留出现次数最多的那个字符, 计算最少翻转几个位置, 使得最终答案发生改变
在这里插入图片描述
如果改变根节点, 那么子节点的选取就要发生改变, 具有递归的性质, 也就是当前问题答案由子问题得到, 设递推状态 f [ i ] f[i] f[i]表示将节点 i i i翻转的最小代价

如何计算状态转移?
考虑当前值是如何计算得到的, 也就是第 n + 1 n + 1 n+1层的状态分类, 分为 ( x , x , x ) (x, x, x) (x,x,x) ( x , x , x ′ ) (x, x, x') (x,x,x), 第一种情况找到两个最小代价相加, 第二种在 ( x , x ) (x, x) (x,x)中选择最小代价, 因为当前层只会取决于 n + 1 n + 1 n+1层数, 因此可以滚动数组优化

#include <bits/stdc++.h>

using namespace std;

const int N = 2e6 + 10, INF = 0x3f3f3f3f;

string s;
int n;
int f[(N << 2) + 10];
int cnt = 1;

int dfs(int u, int l, int r) {
	if (l == r) {
		f[u] = 1;
		return s[r] - '0';
	}
	int ls = ++cnt, ms = ++cnt, rs = ++cnt;

	int len = r - l + 1;
	int l_val = dfs(ls, l, l + len / 3 - 1);
	int m_val = dfs(ms, l + len / 3, l + len / 3 * 2 - 1);
	int r_val = dfs(rs, l + len / 3 * 2, r);

	int cnt0 = 0, cnt1 = 0;
	if (l_val == 0) cnt0++; else cnt1++;
	if (m_val == 0) cnt0++; else cnt1++;
	if (r_val == 0) cnt0++; else cnt1++;
	int now_val = cnt0 > cnt1 ? 0 : 1;
	f[u] = INF;

	//只需要改一个的情况
	if ((now_val == 0 && cnt1 == 1) || (now_val == 1 && cnt0 == 1)) {
		if (l_val == now_val) f[u] = min(f[u], f[ls]);
		if (m_val == now_val) f[u] = min(f[u], f[ms]);
		if (r_val == now_val) f[u] = min(f[u], f[rs]);
	}
	else {
		f[u] = min(f[u], f[ls] + f[ms]);
		f[u] = min(f[u], f[ls] + f[rs]);
		f[u] = min(f[u], f[ms] + f[rs]);
	}
	return now_val;
}

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

	cin >> n >> s;
	s = " " + s;
	dfs(1, 1, s.size() - 1);

	cout << f[1] << "\n";
	return 0;
}

F

算法标签: 贪心, 堆, 枚举, 排序, 优先队列

在这里插入图片描述

思路

首先考虑简单的情况, 假设只有两个序列, 有 N 2 N ^ 2 N2对二元组第 k k k大的值, k ≤ 5 × 1 0 5 k \le 5 \times 10 ^ 5 k5×105, 如果每一步找最大值花的时间很少, 那么可以不停的找, 知道找到 k k k

在这里插入图片描述
对于二维情况, 将 A i A_i Ai B i B_i Bi从大到小排序, 假设 ( i , j ) (i, j) (i,j)是最大值, 下一个最大值一定是 ( i + 1 , j ) (i + 1, j) (i+1,j) ( i , j + 1 ) (i, j + 1) (i,j+1)两个数字中选择, 也就是每次扩展一维中的一个, 需要使用 s e t set set判重, 逐步探索

#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <tuple>

using namespace std;

typedef long long LL;
const int N = 2e5 + 10;

int n, k;
int a[N], b[N], c[N];

struct Node {
	int a, b, c;
	LL res;

	bool operator<(const Node &n) const {
		return res < n.res;
	}
};

LL get(int i, int j, int k) {
	return (LL) a[i] * b[j] + (LL) a[i] * c[k] + (LL) b[j] * c[k];
}

LL get_hash(int x, int y, int z) {
	return (LL) x * N * N + (LL) y * N + z;
}

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

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

	sort(a + 1, a + n + 1, greater<int>());
	sort(b + 1, b + n + 1, greater<int>());
	sort(c + 1, c + n + 1, greater<int>());

	priority_queue<Node> q;
	set<LL> s;
	
	q.push({1, 1, 1, get(1, 1, 1)});
	s.insert(get_hash(1, 1, 1));

	int cnt = 0;
	LL ans = 0;

	while (!q.empty() && cnt < k) {
		auto [x, y, z, res] = q.top();
		q.pop();
		cnt++;
		ans = res;
		if (cnt == k) break;

		if (x + 1 <= n) {
			LL hash = get_hash(x + 1, y, z);
			if (!s.count(hash)) {
				LL new_res = get(x + 1, y, z);
				q.push({x + 1, y, z, new_res});
				s.insert(hash);
			}
		}

		if (y + 1 <= n) {
			LL hash = get_hash(x, y + 1, z);
			if (!s.count(hash)) {
				LL new_res = get(x, y + 1, z);
				q.push({x, y + 1, z, new_res});
				s.insert(hash);
			}
		}
		
		if (z + 1 <= n) {
			LL hash = get_hash(x, y, z + 1);
			if (!s.count(hash)) {
				LL new_res = get(x, y, z + 1);
				q.push({x, y, z + 1, new_res});
				s.insert(hash);
			}
		}
	}

	cout << ans << "\n";
	return 0;
}

G

算法标签: 动态规划, d p dp dp d p dp dp

在这里插入图片描述

相关文章:

  • 笔试专题(三)
  • 26考研——图_图的代码实操(6)
  • uv包简单使用案例
  • 在 Mac 上使用 Poetry 配置环境变量
  • 【外设】之STIM210陀螺仪学习记录
  • 大数据学习(86)-Zookeeper去中心化调度
  • Python_电商日报_不同数据来源清洗整理成一张表
  • javaweb自用笔记:Mybatis
  • 案例实践 | 招商局集团以长安链构建“基于DID的航运贸易数据资产目录链”
  • 基于大模型预测的初治菌阳肺结核诊疗方案研究报告
  • ORBITVU 欧保图,开启自动化摄影新时代
  • 【精心整理】2025 DeepSeek 精品学习资料合集-共50份(教程+原理解读+行业应用+技术实践).zip
  • 关于瑞芯微开发工具(RKDevTool)刷机下载Boot失败原因的研究
  • 2025-3-25算法打卡
  • H3C交接机初始基本配置
  • 论文评估指标
  • 敏捷需求分析之INVEST原则
  • 手机销售终端MPR+LTC项目项目总体方案P183(183页PPT)(文末有下载方式)
  • 《Python全栈开发》第14课:项目部署 - Docker与云服务实战
  • Android设计模式之工厂方法模式
  • 网站备案号在哪里/什么是友情链接?
  • 东莞网页设计费用/seo公司网站推广
  • 网站建设的几种形式/百度站长平台链接
  • 揭阳网站制作托管/精准大数据获客系统
  • 仙居网站开发/分析网站
  • 企业建设网站的方式/seo专员是干什么的