比赛链接

A

题意

有两座塔由红蓝方块组成,分别有 \(n,m\) 个方块,一次操作可以把一座塔塔顶的方块移动到另一座塔的塔顶,问通过操作是否能使每座塔中没有颜色相同的相邻方块。

题解

知识点:贪心。

注意到,操作最多能拆掉一对相邻的方块,因此统计两座塔不合法的对数。

  1. 如果超过 \(1\) 对,那么无解。
  2. 如果只有 \(1\) 对,那么操作一定使得塔顶相对,塔顶若颜色一样就无解,否则有解。
  3. 如果没有不合法的方块,也有解。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int n, m;
cin >> n >> m;
string s, t;
cin >> s >> t;
int mis = 0;
for (int i = 1;i < n;i++) if (s[i] == s[i - 1]) { mis++; }
for (int i = 1;i < m;i++) if (t[i] == t[i - 1]) { mis++; }
if (mis >= 2 || mis == 1 && s.back() == t.back()) return false;
else cout << "YES" << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

B

题意

坐标轴上覆盖了 \(n\) 个线段,指定一个点坐标为 \(k\) ,能否通过删除一些线段使得覆盖指定点的线段严格最多。

题解

知识点:贪心。

直接去除没有覆盖 \(k\) 的线段,此时若 \(k\) 覆盖数严格最多,那么有解;否则,去除任意一条线段,都会使 \(k\) 和一些点同时减 \(1\) ,不会使得 \(k\) 覆盖数严格最多,所以无解。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; bool solve() {
int n, k;
cin >> n >> k;
vector<int> vis(57);
for (int i = 1;i <= n;i++) {
int l, r;
cin >> l >> r;
if (l <= k && k <= r) vis[l]++, vis[r + 1]--;
}
for (int i = 1;i <= 50;i++) vis[i] += vis[i - 1];
bool ok = 1;
for (int i = 1;i <= 50;i++) if (i != k) ok &= vis[k] > vis[i];
if (ok) cout << "YES" << '\n';
else return false;
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << "NO" << '\n';
}
return 0;
}

C

题意

有 \(n\) 杯茶,第 \(i\) 杯茶有 \(a_i\) 毫升。有 \(n\) 个人,每个人每次最多能喝 \(b_i\) 毫升。

第一轮,第 \(i\) 个人喝第 \(i\) 杯茶,第 \(i\) 杯茶减少 \(\min(a_i,b_i)(1\leq i\leq n)\) 毫升。

第二轮,第 \(i\) 个人喝第 \(i-1\) 杯茶,第 \(1\) 个人不喝,第 \(i\) 杯茶减少 \(\min(a_i,b_{i+1})(1\leq i\leq n-1)\) 毫升。

以此类推,问最后每个人喝了多少毫升茶。

题解

知识点:枚举,前缀和,差分,二分。

考虑枚举每杯茶的贡献。第 \(i\) 杯茶会被 \([i,n]\) 内的人喝,但茶会被喝完,所以设 \(sumb\) 为 \(b\) 的前缀和,找到最大的位置 \(j\) 满足 \(sumb_j - sumb_{i-1}\leq a_i \iff sum_{j} \leq sum_{i-1} + a_i\) ,即 \([i,j]\) 的人能喝到自己的上限,第 \(j+1\) 个人能喝到剩下的 \(a_i - (sum_j - sum_{i-1})\) 。

我们用差分数组 \(cnt\) 完成 \([i,j]\) 的区间加 \(1\) ,最后前缀和就能得到第 \(i\) 个人能喝到自己的上限多少次。再用数组 \(delta\) 记录第 \(i\) 个人喝了多少剩下的茶,最后 \(cnt_ib_i + delta_i\) 即第 \(i\) 个人的毫升数。

时间复杂度 \(O(n\log n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; int a[200007], b[200007];
ll sumb[200007];
int cnt[200007];
ll delta[200007];
bool solve() {
int n;
cin >> n;
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++) sumb[i] = sumb[i - 1] + b[i], delta[i] = 0, cnt[i] = 0;
for (int i = 1;i <= n;i++) {
int id = upper_bound(sumb + i, sumb + n + 1, a[i] + sumb[i - 1]) - sumb - 1;
cnt[i]++;
cnt[id + 1]--;
delta[id + 1] += a[i] - (sumb[id] - sumb[i - 1]);
}
for (int i = 1;i <= n;i++) {
cnt[i] += cnt[i - 1];
cout << 1LL * cnt[i] * b[i] + delta[i] << ' ';
}
cout << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

D

题意

给定一个有 \(n\) 个点 \(n\) 条边的无向带权图,保证 \(n\) 为 \(6\) 的倍数,组成 \(\dfrac{n}{3}\) 个三元环: \((1,2,3),(4,5,6),\cdots\) 。

现在给每个点染上红或蓝两种颜色,要求红色有 \(\dfrac{n}{2}\) 个点、蓝色也有 \(\dfrac{n}{2}\) 个点 。

定义一种染色方案的价值为,两端颜色不同的边的权值总和。

设所有染色方案种价值最大为 \(W\) ,问有多少种染色方案的价值为 \(W\) 。

题解

知识点:贪心,排列组合。

显然,一个三元环的最多能贡献两条边,即两红一蓝或两蓝一红,刚好我们可以使得所有三元环都能贡献出两条边,我们对每个三元环贪心地选最大的两条边即可达到最大价值。因此,染色方案必然是每个三元环两红一蓝或两蓝一红,且最大的两条边端点颜色不同。

考虑三元环的分配方案,我们需要一半的两红一蓝另一半两蓝一红,因此方案数是 \(\dbinom{n/3}{n/6}\) 。再考虑每一种分配方案的不同染色方案,显然三边权值相同的三元组能贡献三种方案,而两边权值相同的三元组当且仅当三边中不同的权值是最大值时会贡献两种方案,分别记为 \(cnt_1,cnt_2\) ,则总方案数为 \(3^{cnt_1} \cdot 2^{cnt_2}\cdot \dbinom{n/3}{n/6}\) 。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; const int P = 998244353;
const int N = 3e5 + 7;
namespace CNM {
int qpow(int a, ll k) {
int ans = 1;
while (k) {
if (k & 1) ans = 1LL * ans * a % P;
k >>= 1;
a = 1LL * a * a % P;
}
return ans;
} int fact[N], invfact[N];
void init(int n) {
fact[0] = 1;
for (int i = 1;i <= n;i++) fact[i] = 1LL * i * fact[i - 1] % P;
invfact[n] = qpow(fact[n], P - 2);
for (int i = n;i >= 1;i--) invfact[i - 1] = 1LL * invfact[i] * i % P;
} int C(int n, int m) {
if (n == m && m == -1) return 1; //* 隔板法特判
if (n < m || m < 0) return 0;
return 1LL * fact[n] * invfact[n - m] % P * invfact[m] % P;
}
} int w[300007];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
CNM::init(n / 3);
for (int i = 1;i <= n;i++) cin >> w[i];
int cnt1 = 0, cnt2 = 0;
for (int i = 3;i <= n;i += 3) {
if (w[i - 2] == w[i - 1] && w[i - 1] == w[i]) cnt1++;
else if (w[i] == w[i - 1] || w[i - 1] == w[i - 2] || w[i - 2] == w[i]) {
int mx = max({ w[i - 2],w[i - 1],w[i] });
if (count(w + i - 2, w + i + 1, mx) == 1) cnt2++;
}
}
cout << 1LL * CNM::qpow(3, cnt1) * CNM::qpow(2, cnt2) % P * CNM::C(n / 3, n / 6) % P << '\n';
return 0;
}

E

题意

有 \(n\) 个怪物,第 \(i\) 个怪物的血量有 \(h_i\) ,血量降为 \(0\) 时立刻死亡,你有两种攻击方式:

  1. 指定一个怪物,对其普通攻击,造成 \(1\) 点伤害,消耗 \(1\) 点魔法。普通攻击可以使用无限次。

  2. 指定一个怪物,对其释放爆炸魔法,造成的伤害取决于注入的魔法,如果想要消耗 \(x\) 点魔法注入其中,会造成 \(x\) 点伤害。

    爆炸魔法具有连锁性,如果被魔法击中的怪物死了,假设是第 \(i\) 个怪物,那么 \(i-1,i+1\) 两个怪物会受到 \(h_i-1\) 的伤害,以此类推,直至没有怪物死掉。这个魔法只能使用一次。

问,最少需要多少魔法能消灭所有怪物。

题解

知识点:枚举,贪心,单调栈。

显然,我们可以枚举释放爆炸魔法的位置,取造成伤害最多的即可。

对于每个位置,都可以向两侧扩展,不妨先考虑左侧部分。

我们设 \(l_i\) 为在第 \(i\) 个位置释放爆炸魔法后,左侧(包括自己)能造成的最大伤害。我们考虑在 \(i\) 处依次向左扩展的两种情况:

  1. 对于 \(j<i\) ,若 \(h_j \geq h_i - (i-j)\) ,则说明 \(j\) 不能被消灭,但我们可以在之前通过普通攻击把血量降到可以消灭的血量,因此还是可以造成 \(h_i-(i-j)\) 的伤害。
  2. 对于 \(j<i\) ,一旦出现 \(h_j < h_i-(i-j)\) ,则说明 \(j\) 虽然能被消灭,但会降低之后的魔法伤害,后续计算会由 \(h_j\) 直接支配,我们通过 \(l_i\) 直接转移即可,并停止扩展。

注意到,如此操作的复杂度是平方的,我们考虑优化复杂度。我们可以将条件中的变量转换为 \(h_j - j,h_i -i\) ,就可以绑定成一个值了。我们发现,满足情况1造成的伤害都是连续减 \(1\) 的,而满足情况 \(2\) 后直接加 \(f_j\) 后停止,所以我们只要求左侧第一个满足 \(h_j - j < h_i-i\) 的位置 \(j\) ,就可以直接得到造成的伤害 \(l_j + \dfrac{(i-j)(h_i-(i-j)+1 + h_i)}{2}\) 。

显然,这个过程可以用单调递增栈实现的,其可以维护一个字典序最小的极长递增子序列(极长递增子序列指,一个不能继续递增的递增子序列),而子序列相邻两元素之间的在原数组的其他元素,一定都大于等于这两个元素,因此是不需要比较的。于是,对于一个值,我们比较维护的子序列,就可以跳过一些不需要比较的位置。整个过程,每个元素只会出入一次维护的子序列,因此复杂度是线性的。

对于右侧,我们把 \(h\) 反转,重新算一遍 \(h_i-i\) 做相同的事情得到 \(r_i\) ,再将 \(r_i\) 反转,\(h\) 复原。最后,设血量总和为 \(sum\) ,枚举每个位置 \(i\) 得到 \(sum - (l_i + r_i - h_i) + h_i\) 取最小值。

时间复杂度 \(O(n)\)

空间复杂度 \(O(n)\)

代码

#include <bits/stdc++.h>
using namespace std;
using ll = long long; int n;
int h[300007], hi[300007];
ll l[300007], r[300007];
void calc(ll *f) {
stack<int> stk;
stk.push(0);
for (int i = 1;i <= n;i++) {
while (stk.size() > 1 && hi[stk.top()] >= hi[i]) stk.pop();
int len = min(h[i], i - stk.top());
f[i] = f[stk.top()] + 1LL * len * (h[i] + (h[i] - len + 1)) / 2;
stk.push(i);
}
} bool solve() {
cin >> n;
ll sum = 0;
for (int i = 1;i <= n;i++) cin >> h[i], sum += h[i]; for (int i = 1;i <= n;i++) hi[i] = h[i] - i;
calc(l); reverse(h + 1, h + n + 1);
for (int i = 1;i <= n;i++) hi[i] = h[i] - i;
calc(r); reverse(h + 1, h + n + 1);
reverse(r + 1, r + n + 1);
ll ans = 1e18;
for (int i = 1;i <= n;i++) ans = min(ans, sum - (l[i] + r[i] - h[i]) + h[i]);
cout << ans << '\n';
return true;
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
if (!solve()) cout << -1 << '\n';
}
return 0;
}

Educational Codeforces Round 143 (Rated for Div. 2) A-E的更多相关文章

  1. Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - C. Magic Ship Time Limit: 2000 mSec P ...

  2. Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems(动态规划+矩阵快速幂)

    Problem   Educational Codeforces Round 60 (Rated for Div. 2) - D. Magic Gems Time Limit: 3000 mSec P ...

  3. Educational Codeforces Round 43 (Rated for Div. 2)

    Educational Codeforces Round 43 (Rated for Div. 2) https://codeforces.com/contest/976 A #include< ...

  4. Educational Codeforces Round 35 (Rated for Div. 2)

    Educational Codeforces Round 35 (Rated for Div. 2) https://codeforces.com/contest/911 A 模拟 #include& ...

  5. Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings

    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) F. Isomorphic Strings 题目连接: http://cod ...

  6. Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

    Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://code ...

  7. Educational Codeforces Round 63 (Rated for Div. 2) 题解

    Educational Codeforces Round 63 (Rated for Div. 2)题解 题目链接 A. Reverse a Substring 给出一个字符串,现在可以对这个字符串进 ...

  8. Educational Codeforces Round 39 (Rated for Div. 2) G

    Educational Codeforces Round 39 (Rated for Div. 2) G 题意: 给一个序列\(a_i(1 <= a_i <= 10^{9}),2 < ...

  9. Educational Codeforces Round 48 (Rated for Div. 2) CD题解

    Educational Codeforces Round 48 (Rated for Div. 2) C. Vasya And The Mushrooms 题目链接:https://codeforce ...

  10. Educational Codeforces Round 60 (Rated for Div. 2) 题解

    Educational Codeforces Round 60 (Rated for Div. 2) 题目链接:https://codeforces.com/contest/1117 A. Best ...

随机推荐

  1. FluentFTP能连接却报未将对象引用设置到对象的实例。

    本来项目中用的好好的FTP下载传输,不知道从什么时候开始读取不到了,也上传不了.实际读取的是本地缓存的.因为同事上传不了文件和图片才发现.上源码! #region 下载文件 static byte[] ...

  2. 如何安装Visual Studio Community2022

    如何安装Visual Studio Community2022 Visual Studio是一款强大的IDE(集成开发环境),对于初学者可以选择使用社区版,下面是Visual Studio Commu ...

  3. 协程Part1-boost.Coroutine.md

    首先,在计算机科学中 routine 被定义为一系列的操作,多个 routine 的执行形成一个父子关系,并且子 routine 一定会在父 routine 结束前结束,也就是一个个的函数执行和嵌套执 ...

  4. Apache手动安装教程及报错解决梳理

    操作参考教程:https://www.cnblogs.com/haw2106/p/9839655.html 下载地址(例):wget https://dlcdn.apache.org/httpd/ht ...

  5. js 定时器(setInterval)

    js 定时器 分类 编程技术 js 定时器有以下两个方法: setInterval() :按照指定的周期(以毫秒计)来调用函数或计算表达式.方法会不停地调用函数,直到 clearInterval() ...

  6. choices参数

    目录 一:choices参数 1.choices参数作用 2.列举: 3.choices效果 二:choices使用 1.创建字段类型 2.验证choices 3.使用测试脚本 4.将manage.p ...

  7. Django查看内部sql语句的方式

    一:查看内部sql语句的方式 方式1(queryset对象才能够点击query查看内部的sql语句) res = models.User.objects.values_list('name', 'ag ...

  8. HNCTF的pyjail做题过程详解

    简述: 因为本人对python的内置函数理解也不是深入,在做题过程中也是靠着出题人的hint和google大法才做出来几题,详细的解题过程和知识点讲解可以看一下春哥的知乎,[PyJail] pytho ...

  9. BFS广度优先搜索例题分析

    洛谷P1162 填涂颜色 题目描述 由数字 \(0\) 组成的方阵中,有一任意形状闭合圈,闭合圈由数字 \(1\) 构成,围圈时只走上下左右 \(4\) 个方向.现要求把闭合圈内的所有空间都填写成 \ ...

  10. vivo 游戏中心低代码平台的提效秘诀

    作者:vivo 互联网服务器团队- Chen Wenyang 本文根据陈文洋老师在"2022 vivo开发者大会"现场演讲内容整理而成.公众号回复[2022 VDC]获取互联网技术 ...