Educational Codeforces Round 152 (Rated for Div. 2)

传送阵

T1 Morning Sandwich

题目大意

t 个测试,每个测试给三个正整数 b,c,h,分别表示面包和两种馅料的个数,每两个面包之间必须放一个馅料,问最多能摆几层?

思路

我们发现 c,h 所表示的两种馅料其实相差不大,所以我们可以分两种情况

  1. a>c+h

    因为开头总是面包,所以要+1,我们把(馅料+面包)看成一组,一共有 (c+h) 组,每组 2 层,一共有 1+2(c+h)

  2. ac+h

    我们不停放面包,直到把面包放完,同样把(馅料+面包)看成一组,这里就有 2n 层,但由于开头要放一个,无法配对,所以只有 2n1

#include <bits/stdc++.h> using namespace std; int n, a, b, c; int main() { cin >> n; for (int i = 1; i <= n; i++) { cin >> a >> b >> c; if (a > b + c) cout << 1 + (b + c) * 2 << endl; else if (a <= b + c) cout << a * 2 - 1 << endl; } return 0; }

T2 Monsters

题目大意

已知 n 个怪的血量序列 a,每次可以对最高血量的怪造成 k 点伤害,求怪死亡的顺序。

思路

我们发现总有一个状态是所有怪物都没死,但是所有怪物的血量都小于等与 k ,这个时候易得所有怪物的血量为 aimodk ,但当 aik 的倍数时,此时的血量为 k

我们可以根据这个状态的血量进行排序,排序优先级为先排 aimodk ,若血量相同则按顺序排。

#include <bits/stdc++.h> using namespace std; bool cmp(pair<int, int> a, pair<int, int> b) { if (a.first == b.first) return a.second < b.second; return a.first > b.first; } void solve() { vector<pair<int, int>> a; int n, k; cin >> n >> k; for (int i = 1; i <= n; i++) { int start; cin >> start; if (start > k) start = start % k == 0 ? k : start % k; a.push_back({start, i}); } sort(a.begin(), a.end(), cmp); for (auto p : a) cout << p.second << ' '; cout << endl; } int main() { int t; cin >> t; while (t--) solve(); return 0; }

T3 Binary String Copying

题目大意

t 个询问,每个询问给两个正整数 n,m 分别表示字符串 s 长度,操作次数

每次操作给两个数 l,r 表示将 l,r 区间进行排序,问在这些操作中字符串有多少可能

思路

000...111... 明显进行排序时是不会变的我们把它记为一个特殊的状态

我们建立两个数组 pre,next 分别代表第 i 个数之前的第一个 0, 第 i 个数之后的第一个 1

然后我们发现对于每一个区间都有一个有效区间为[l,r] 中的第一个 1 到最后一个 0 也就是

000...[101001....0]111...

接下来对于同一个区间进行排序显然只会有同一种结果,所以我们用[nextl,prer] 为一个状态

这里对于产生同一种状态的话显然只能保留 1 种。

#include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; string str; cin >> str; vector<int> pre0(n, -1), next1(n, n); for (int i = 0; i < n; i++) { if (i > 0) pre0[i] = pre0[i - 1]; if (str[i] == '0') pre0[i] = i; if (n - i - 1 < n - 1) next1[n - i - 1] = next1[n - i]; if (str[n - i - 1] == '1') next1[n - i - 1] = n - i - 1; } set<pair<int, int>> st; while (m--) { int l, r; cin >> l >> r; if (next1[l - 1] > pre0[r - 1]) st.emplace(-1, -1); else st.emplace(next1[l - 1], pre0[r - 1]); } cout << st.size() << endl; } int main() { int t; cin >> t; while (t--) solve(); return 0; }

T4 Array Painting

题目大意

n 个格子,第 i 个格子上的数字为 ai。一开始,所有格子都是蓝色的。你可以进行以下两种操作若干次:

一、花费一枚硬币,把一个蓝色的格子染成红色。

二、选择一个红色的且数字不为 0 的格子以及其旁边的一个蓝色的格子,把红色格子上面的数字减一,并把蓝色格子染成红色。

求至少要花费多少枚硬币,使得所有格子都被染成红色?

思路

我们考虑 dp

dpi,j 为考虑前 i 个,第 i 格状态为 j 的最小代价。

首先我们肯定要先将第 i 个自己涂了,这里只有两种涂法,一个是直接涂,一个是从别人那里拿过来过来

dpi,ai=min{dpi1,0+1,dpi1,1,dpi1,2}

然后我们发现一种情况

101112

当我们从 2 这个地方开始时,往左覆盖,直到覆盖到 0 这个位置,因为如果不是 0 就一定 >0 能够继续往前覆盖(自力更生)

pre0i 为 从 i 往前走第一个出现 0 的位置

dpi,j=min{dpprei1,1,dpprei1,2,dpprei1,0}+1

这里这么写其实是把 [1,i] 分成了两个部分,其中 [1,prei1] 的价值为 dpprei1,(0/1/2)

[prei,i] 的价值为 1 ,然后两者相加即可

#include <bits/stdc++.h> using namespace std; const int N = 2e5 + 10; int n; int a[N], pre0[N], dp[N][3]; int main() { //输入 cin >> n; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); // 初始化 memset(dp, 0x3f, sizeof(dp)); dp[0][1] = dp[0][0] = dp[0][2] = 0; dp[1][a[1]] = 1; //处理数据 for (int i = 1; i <= n; i++) pre0[i] = a[i] ? pre0[i - 1] : i; //动态规划解决问题 for (int i = 2; i <= n; i++) { dp[i][a[i]] = min(dp[i - 1][0] + 1, min(dp[i - 1][1], dp[i - 1][2])); if (a[i] > 0) dp[i][a[i] - 1] = min(dp[pre0[i] - 1][0], min(dp[pre0[i] - 1][1], dp[pre0[i] - 1][2])) + 1; } cout << min({dp[n][0], dp[n][1], dp[n][2]}); return 0; }

__EOF__

本文作者ljfyyds
本文链接https://www.cnblogs.com/ljfyyds/p/17590403.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   ljfyyds  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示