Edu162
Edu162[A-E]
A. Moving Chips[Trick]
功能区分为
您可以执行以下操作任意次数(可能为零):选择一个筹码并将其移动到 左侧最近的空闲单元。您可以选择任何您想要的芯片,只要其左侧至少有一个空闲单元即可。当您移动芯片时,操作前所在的单元格就会空闲。
您的目标是以这样的方式移动芯片,使得它们形成一个块,并且它们之间没有任何空闲单元。您必须执行的最少操作次数是多少?
分析
我们找出最左边和最右边的芯片
目标使得
我们每次移动最右边的芯片,可以填补最右边的空白,并将空出的空白格移到
这样我们每次移动都可以减少一个空白格的数量
我们的目标是让空白格的数量为
所需的操作次数就是一开始区间中空白格的数量
code
Submission #247902579 - Codeforces
// Codeforces - Educational Codeforces Round 162 (Rated for Div. 2) A. Moving
// Chips https://codeforces.com/contest/1923/problem/0 2024-02-23 22:35:51
#include <bits/stdc++.h>
using namespace std;
#define all(a) begin(a), end(a)
#define int long long
int n, m;
void solve() {
cin >> n;
vector<int> a(n), s(n);
for (auto &i : a) cin >> i;
for (int i = 0; i < n; i++)
if (i)
s[i] = s[i - 1] + a[i];
else
s[i] = a[i];
int l = 0, r = n - 1;
while (l < n and a[l] == 0) l++;
while (r >= 0 and a[r] == 0) r--;
if (r < l)
cout << "0\n";
else if (l)
cout << -s[r] + s[l - 1] + r - l + 1 << "\n";
else
cout << -s[r] + r - l + 1 << "\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int __;
cin >> __;
while (__--) solve();
return 0;
}
B. Monsters Attack![Trick]
您正在玩电脑游戏。该游戏的当前等级可以建模为一条直线。您的角色位于该行的点
每一秒都会发生以下情况:
- 首先,你向怪物发射最多
颗子弹。每颗子弹只瞄准一个怪物并使其生命值降低 。对于每颗子弹,您可以任意选择其目标(例如,您可以向一个怪物发射所有子弹,向不同的怪物发射所有子弹,或选择任何其他组合)。任何怪物都可以成为子弹的目标,无论其位置和任何其他因素如何; - 然后,所有生命值小于等于
的活着的怪物都会死亡; - 然后,所有活着的怪物都会向您靠近
点(您左边的怪物将其坐标增加 ,您右侧的怪物将其坐标减少 )。如果任何怪物到达你的角色(移动到点 ),你就输了。
您能生存并杀死所有
分析
这个题也是一个小Trick
我们维护前缀
如果坐标为负数我们就取绝对值 转移到正数 方便处理
code
Submission #247906784 - Codeforces
// Codeforces - Educational Codeforces Round 162 (Rated for Div. 2) B. Monsters
// Attack! https://codeforces.com/contest/1923/problem/B 2024-02-23 22:47:36
#include <bits/stdc++.h>
using namespace std;
#define all(a) begin(a), end(a)
#define int long long
int n, k;
void solve() {
cin >> n >> k;
vector<int> a(n), x(n);
for (auto &i : a) cin >> i;
for (auto &i : x) cin >> i;
map<int, int> mp;
for (int i = 0; i < n; i++)
if (x[i] < 0)
mp[-x[i]] += a[i];
else
mp[x[i]] += a[i];
int res = 0;
for (auto [v, w] : mp)
if (res + w <= v * k)
res += w;
else
return (void)(cout << "NO\n");
cout << "YES\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int __;
cin >> __;
while (__--) solve();
return 0;
}
C. Find B [贪心]
如果存在长度为
; 对于从 到 的每个索引 ; 对于从 到 的每个索引 。
给您一个长度为
您必须回答
分析
对于一个数组
如果存在相同长度的另一个数组
使得两个数组之和相同
另一个数组每个位置都与当前数组的不同
而且另一个数组的每个位置都是大于0 的
贪心的来想
就让之前大于1 的地方全都是1
把之前是1的地方都填上2
剩余量大于等于0就行
code
Submission #247922876 - Codeforces
// Codeforces - Educational Codeforces Round 162 (Rated for Div. 2) C. Find B
// https://codeforces.com/contest/1923/problem/C 2024-02-23 22:52:06
#include <bits/stdc++.h>
using namespace std;
#define all(a) begin(a), end(a)
#define int long long
int n, q;
void solve() {
cin >> n >> q;
vector<int> c(n + 1), s(n + 1), cnt1(n + 1);
for (int i = 1; i <= n; i++) cin >> c[i];
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + c[i];
for (int i = 1; i <= n; i++) cnt1[i] = cnt1[i - 1] + (c[i] == 1);
while (q--) {
int l, r;
cin >> l >> r;
if (l == r) {
cout << "NO\n";
continue;
}
int res = s[r] - s[l - 1] - cnt1[r] + cnt1[l - 1] - r + l - 1;
if (res >= 0)
cout << "YES\n";
else
cout << "NO\n";
}
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int __;
cin >> __;
while (__--) solve();
return 0;
}
D. Slimes[二分]
有
每一秒,都会发生以下情况:恰好一个史莱姆会吃掉它的邻居之一,并根据被吃掉的邻居的大小来增加其大小。只有当史莱姆严格大于邻居时,它才能吃掉它的邻居。如果没有严格大于其邻居之一的史莱姆,则该过程结束。
例如,假设
- 首先,第
个史莱姆吃掉了第 个史莱姆。第 个史莱姆的大小变为 ,第 个史莱姆被吃掉。 - 然后,
-rd 史莱姆吃掉 -st 史莱姆(它们是邻居,因为 -nd 史莱姆已经被吃掉了)。 -rd 史莱姆的大小变为 , -st 史莱姆被吃掉。 - 然后,第
个史莱姆吃掉第 个史莱姆。第 个史莱姆的大小变成了 ,第 个史莱姆被吃掉。 - 然后,第
个史莱姆吃掉第 个史莱姆(它们是邻居,因为第 个史莱姆已经被吃掉了)。第 个史莱姆的大小变成了 ,第 个史莱姆被吃掉。
对于每个史莱姆,计算该史莱姆被另一个史莱姆吃掉所需的最短秒数(在该过程的所有可能方式中),或者报告这是不可能的。
分析
先处理能否在一开始被身边的吃掉
找到最近的未被吃掉的
否则的话就二分离当前位置的距离
由于相同大小的 是不能互相吞噬的
所以我们把大小看成颜色
维护每个颜色的左右端点
二分的时候跳过相邻的颜色段
当有两个及以上的颜色段,这两段区间便可以合成一个很大的 怪物
code
Submission #247951109 - Codeforces
// Codeforces - Educational Codeforces Round 162 (Rated for Div. 2) D. Slimes
// https://codeforces.com/contest/1923/problem/D 2024-02-23 23:18:47
#include <bits/stdc++.h>
using namespace std;
#define all(a) begin(a), end(a)
#define int long long
int n, m;
void solve() {
cin >> n;
vector<int> a(n + 1), L(n + 1), R(n + 1);
for (int i = 1; i <= n; i++) cin >> a[i];
vector<int> ans(n + 1, n + 1);
for (int i = 1; i <= n; i++) {
if (i < n)
if (a[i + 1] > a[i]) ans[i] = 1;
if (i > 1)
if (a[i - 1] > a[i]) ans[i] = 1;
}
for (int i = 1; i <= n; i++) L[i] = R[i] = i;
for (int i = 2; i <= n; i++)
if (a[i] == a[i - 1]) L[i] = L[i - 1];
for (int i = n - 1; i >= 1; i--)
if (a[i] == a[i + 1]) R[i] = R[i + 1];
vector<int> s(n + 1);
for (int i = 1; i <= n; i++) s[i] = s[i - 1] + a[i];
for (int i = 1; i <= n; i++) {
if (ans[i] == n + 1) {
if (i < n) {
int l = R[i + 1] + 1LL, r = n;
while (l <= r) {
int mid = l + r >> 1;
if (s[mid] - s[i] > a[i])
ans[i] = min(ans[i], mid - i), r = mid - 1;
else
l = mid + 1;
}
}
if (i > 1) {
int l = 1, r = L[i - 1] - 1LL;
while (l <= r) {
int mid = l + r >> 1;
if (s[i - 1] - s[mid - 1] > a[i])
ans[i] = min(ans[i], i - mid), l = mid + 1;
else
r = mid - 1;
}
}
}
}
for (auto &i : ans)
if (i == n + 1) i = -1;
for (int i = 1; i <= n; i++) cout << ans[i] << " \n"[i == n];
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int __;
cin >> __;
while (__--) solve();
return 0;
}
E. Count Paths[启发式合并]
给您一棵树,由
如果满足以下条件,则树的简单路径称为美丽路径:
- 它至少由
个顶点组成; - 路径的第一个和最后一个顶点具有相同的颜色;
- 路径上没有其他顶点与第一个顶点具有相同的颜色。
数数树上美丽简单的路径有多少条。请注意,路径被视为无向(即从
分析
我们可以知道答案有两种
一种是父子链上的选择
另一种是一个节点的不同孩子之间
对于第一种我们需要维护 子树中有没有这个父亲的颜色
对于第二种我们需要维护 子树中有多少链有 相同的颜色
于是我们可以用map<int,int>
来维护每一种颜色
但是直接维护是
但是有一种奇妙的东西叫做启发式合并
简而言之就是在合并信息的时候,将
可以发现每一次合并对于任意一个移动的点,所在的区间的大小都会扩增至少
所以可以在
时间复杂度的上界是
code
codeforces.com/contest/1923/submission/248062684
// Codeforces - Educational Codeforces Round 162 (Rated for Div. 2) E. Count
// Paths https://codeforces.com/contest/1923/problem/E 2024-02-23 23:57:48
#include <bits/stdc++.h>
using namespace std;
#define all(a) begin(a), end(a)
#define int long long
int n, m;
void solve() {
cin >> n;
vector<int> col(n);
for (auto &i : col) cin >> i;
vector<vector<int>> G(n);
for (int i = 1; i < n; i++) {
int x, y;
cin >> x >> y;
x--, y--;
G[x].emplace_back(y);
G[y].emplace_back(x);
}
vector<map<int, int>> mp(n);
int ans = 0;
auto merge = [&](int i, int j) -> void {
if (mp[i].size() < mp[j].size()) swap(mp[i], mp[j]);
for (auto [x, y] : mp[j]) mp[i][x] += y;
};
auto dfs = [&](auto self, int u, int fa) -> void {
mp[u][col[u]]++;
for (auto it : G[u]) {
if (it == fa) continue;
self(self, it, u);
if (mp[it].contains(col[u]))
ans += (mp[it][col[u]] * mp[it][col[u]] - mp[it][col[u]]) / 2LL;
merge(u, it);
}
ans += mp[u][col[u]] - 1;
mp[u][col[u]] = 1;
};
dfs(dfs, 0, 0);
for (auto [x, y] : mp[0]) ans += (y * y - y) / 2LL;
cout << ans << "\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int __;
cin >> __;
while (__--) solve();
return 0;
}
本文作者:liangqianxing
本文链接:https://www.cnblogs.com/liangqianxing/p/18031876
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步