Educational Codeforces Round 164 (Rated for Div. 2)
写在前面
比赛地址:https://codeforces.com/contest/1954
本来有机会上大分但是唐了 E 没调出来呃呃。
小号比大号分高了呃呃以后想休闲直接打大号了哈哈
A
数学。
若要将 个位置全部涂成颜色 ,则一定要修改 次。
则一个显然想法是最小化 ,由鸽巢原理可知 。
则当且仅当 输出 YES
,否则 NO
。
复制复制// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long //============================================================= //============================================================= //============================================================= int main() { //freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { int n, m, k; std::cin >> n >> m >> k; std::cout << ((k < n - ceil(1.0 * n / m)) ? "YES" : "NO") << "\n"; } return 0; }
B
枚举。
手玩下发现有解当且仅当原 beatuiful
数列所有位置并不全相等,且由性质可知,此时数列一定满足:
- 修改为全部相等数列后,所有位置均为 。
- 不存在两个连续的不等于 的位置。
记所有非 的位置为 ,则将数量修改为非 beautiful
有两种方案:
- 将 调整到数列首或数列尾。
- 调整使得两个 相邻。
考虑记 ,,则答案即为:
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 3e5 + 10; //============================================================= int n, a[kN]; //============================================================= //============================================================= int main() { //freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> n; std::vector<int> pos; pos.push_back(0); for (int i = 1; i <= n; ++ i) { std::cin >> a[i]; if (a[i] != a[1]) pos.push_back(i); } pos.push_back(n + 1); if (pos.size() == 2) { std::cout << -1 << "\n"; } else { int ans = n; for (int i = 1, sz = pos.size(); i < sz; ++ i) { ans = std::min(ans, pos[i] - pos[i - 1] - 1); } std::cout << ans << "\n"; } } return 0; } /* 1 8 1 1 2 1 2 1 1 1 */
C
数学,贪心。
考虑有这样两个数:
考虑拆一下多项式乘法,则有:
发现上式中第一项不受修改影响,因为有与指数相乘的原因,第二项的影响比第三项大得多,于是仅需考虑按照位数递减,最大化第二项的影响即可。
于是一个显然的想法是从高到低枚举各位 ,找到第一个 的位置 。记第 位较大的数为 ,另一个数为 ,由上式可知为了最大化 仅需调整使得 各位 中满足 即可。
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 110; //============================================================= std::string x, y; bool tag[kN]; //============================================================= void modify(int pos_, int len_, std::string &s_, std::string &t_) { for (int i = pos_; i < len_; ++ i) { if (s_[i] > t_[i]) { std::swap(s_[i], t_[i]); } } } //============================================================= int main() { //freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); int T; std::cin >> T; while (T --) { std::cin >> x >> y; for (int i = 0, len = x.length(); i < len; ++ i) tag[i] = 0; for (int i = 0, len = x.length(); i < len; ++ i) { if (x[i] == y[i]) continue; else if (x[i] > y[i]) modify(i + 1, len, x, y); else modify(i + 1, len, y, x); break; } std::cout << x << "\n" << y << "\n"; } return 0; }
D
数学,DP。
妈的真有用到同一个结论的题啊哈哈
考虑对于一组选出的球 应如何分组才可令分组数量最少。
- 发现若无法令各组均为 2,则剩下的球一定为数量最多的一种。
- 则一种最优的分配方案是每次选出数量最多的一种,与数量最少的一种,然后从中各选出一个配成一组。
这个分配方式怎么这么熟悉?翻了下刚打的湖南多校发现有道还更强的题:https://codeforces.com/gym/512144/problem/C,要求将 种颜色的物品按每组 个分组,则有结论最少分组数为:
在本题中 。
则若已知选择的所有球中数量最多的球的数量,再考虑球的总数即可求得最少分组数。发现题目给定额外性质:,球的总数很少,于是考虑直接大力枚举 ,再大力枚举球的个数,并考虑有多少种方案选出满足条件的一组球。
于是先将 升序排序,然后考虑 DP,记 表示从升序排序后的 ,选出满足 的子序列 的方案数, 表示钦定选出的最大数量的球为 时对答案的贡献。初始化 ,则有:
答案即为 。
发现这个式子太背包了,套路地滚动数组即可。总时间复杂度 级别。
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 5010; const LL p = 998244353; //============================================================= int n, s, a[kN]; LL ans, sum[kN]; //============================================================= //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); std::cin >> n; for (int i = 1; i <= n; ++ i) { std::cin >> a[i]; s += a[i]; } sum[0] = 1; std::sort(a + 1, a + n + 1); for (int i = 1; i <= n; ++ i) { for (int j = s; j >= a[i]; -- j) { LL size = std::max(1ll * a[i], (LL)ceil(1.0 * j / 2.0)); LL delta = sum[j - a[i]] * size % p; ans = (ans + delta) % p; sum[j] = (sum[j] + sum[j - a[i]]) % p; } // std::cout << ans << "---\n"; } std::cout << ans << "\n"; return 0; }
E
枚举,数据结构。
唉场上实现拉了没做出来亏死。
手玩发现每次操作后数列的变化形式如下:
- 进行若干次操作后,某些位置变为非正,数列被分为若干独立的子区间。
- 对每个子区间独立地重复上述操作。
发现操作的顺序是无所谓的,甚至操作的对象也是无所谓的,因为每次操作会影响整个极大区间,可以保证每次合法的操作都是有贡献的。
于是考虑每轮按顺序枚举当前所有区间,然后对当前所有区间仅进行一次操作。发现当第 轮操作结束时,当前所有区间一定为满足 的极大区间。考虑记满足 的所有极大区间数量为 ,则对于某个确定的 ,答案可以形式化地表示为:
发现上式是一个调和级数的形式,可以 地枚举所有有贡献的项,仅需考虑如何快速预处理 。考虑通过按权值递减不断地向数列中加数,在此过程中维护有多少个极大区间 。如当前插入到权值为 的位置 ,考虑加入 后会使得区间数量增加,还是会合并当前某些区间导致区间数量减少:
- 首先令 。
- 检查数列中 的前驱 :若 或不存在则令 。
- 检查数列中后继 :若 或不存在则令 。
上述过程可直接使用 set
维护,预处理后再调和级数地枚举贡献并求得答案即可。则总时间复杂度 级别,其中 。
注意为了防止 RE,必须先在 set
中插入极小极大值。
// /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 1e5 + 10; //============================================================= int n, maxa, a[kN]; std::vector <int> pos[kN]; std::set<int> s; LL nowcnt, cnt[kN], ans[kN]; //============================================================= void init() { s.insert(-kN); s.insert(kN); } void insert(int pos_) { ++ nowcnt; std::set<int>::iterator next = s.upper_bound(pos_); std::set<int>::iterator pre = std::prev(next); if ((*pre) == pos_ - 1) -- nowcnt; if ((*next) == pos_ + 1) -- nowcnt; s.insert(pos_); } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); std::cin >> n; for (int i = 1; i <= n; ++ i) { std::cin >> a[i]; maxa = std::max(maxa, a[i]); pos[a[i]].push_back(i); } init(); for (int i = maxa; i; -- i) { for (auto p: pos[i]) insert(p); cnt[i] = nowcnt; } // for (int i = 1; i <= maxa; ++ i) std::cout << cnt[i] << " "; for (int i = maxa; i; -- i) { for (int j = 0; i * j < maxa; ++ j) { ans[i] += 1ll * cnt[i * j + 1]; } } for (int i = 1; i <= maxa; ++ i) std::cout << ans[i] << " "; return 0; }
F
咕咕~
写在最后
学到了什么:
- D:真能做到原啊草
- E:
set
查询元素,求前驱后继,可用于添加数列元素过程中区间合并。为了防止 RE 必须先在set
中插入极小极大值。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话