2024 暑假友谊赛 3

news/2025/1/15 17:32:06/文章来源:https://www.cnblogs.com/Kescholar/p/18341364

2024 暑假友谊赛 3

A - A

CodeForces - 1187E

思路

\(f_i\) 表示以 \(i\) 为根的子树产生的贡献,则有 \(f_i=size_i+\sum\limits_{j\in son_i} f_j\),即起初选定 \(i\) 为起点后产生 \(size_i\) 的贡献,后续是它的子树产生的贡献。

但这样以不同根节点去求贡献是 \(O(n^2)\) 的,所以考虑换根 dp。

\(dp_i\) 表示为以 \(i\) 为根的答案。

image

以上图为例,设整棵树大小为 \(n\)

\[dp_x=n+\sum\limits_{v\in substree_x}f_v(\text{$substrr_x$表示x的子树})\\ \]

\[dp_x=n+\sum\limits_{v\in Son_x|v\ne y}f_v+f_y\\ \]

\[dp_x=n+\sum\limits_{v\in Son_x|v\ne y}f_v+size_y+\sum\limits_{u\in Son_y|u\ne x}f_u\\ \]

\[dp_x=n+\sum\limits_{v\in Son_x|v\ne y}f_v+(n-size_y) +size_y+\sum\limits_{u\in Son_y|u\ne x}f_u-(n-size_y)\\ \]

\[dp_x=n+f_x+size_y+\sum\limits_{u\in Son_y|u\ne x}f_u-(n-size_y)\\ \]

\[且 dp_y=n+\sum\limits_{u\in subtree_y}f_u=n+fx+\sum\limits_{u\in Son_y|u\ne x}f_u\\ \]

\[\therefore dp_x=dp_y+2\times size_y-n\\ dp_y=n+dp_x-2\times size_y \]

即换根 dp 最终转移方程。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector g(n + 1, vector<int>());for (int i = 1; i < n; i ++) {int u, v;cin >> u >> v;g[u].emplace_back(v);g[v].emplace_back(u);}vector<i64> f(n + 1), dp(n + 1), siz(n + 1);auto dfs = [&](auto && self, int u, int fa)->void{siz[u] = 1;for (auto v : g[u]) {if (v == fa) continue;self(self, v, u);siz[u] += siz[v];f[u] += f[v];}f[u] += siz[u];};dfs(dfs, 1, 0);i64 ans = 0;ans = dp[1] = f[1];auto dpdfs = [&](auto && self, int u, int fa)->void{if (u != 1) {dp[u] = dp[fa] + n - 2 * siz[u];ans = max(ans, dp[u]);}for (auto v : g[u]) {if (v == fa) continue;self(self, v, u);}};dpdfs(dpdfs, 1, 0);cout << ans << '\n';return 0;
}

B - B

CodeForces - 977D

思路

很经典的一道题,把能被 \(3\) 整除或者能 \(× 2\) 得到的数看成由 \(x\)\(y\) 的一条有向边,这样就转换成了 \(DAG\) 模型,要求一条长度为 \(n\) 的变化方案,其实就是这个模型上的最长路,上拓扑序即可。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector<i64> a(n + 1);for (int i = 1; i <= n; i ++)cin >> a[i];vector<int> in(n + 1);vector g(n + 1, vector<int>());for (int i = 1; i <= n; i ++) {for (int j = 1; j <= n; j ++) {if (j == i) continue;if (a[i] * 2 == a[j]) {g[i].push_back(j);in[j] ++;}if (a[i] % 3 == 0 && a[i] / 3 == a[j]) {g[i].push_back(j);in[j] ++;}}}queue<int> Q;for (int i = 1; i <= n; i ++) {if (!in[i]) {Q.push(i);}}vector<int> ans;while (Q.size()) {auto u = Q.front();Q.pop();ans.push_back(u);for (auto v : g[u]) {if (!--in[v]) {Q.push(v);}}}for (auto i : ans)cout << a[i] << " \n"[i == ans.back()];return 0;
}

C - C

CodeForces - 1368D

思路

注意到选择的 \(x\)\(y\) 会变成两个数 \(x\& y\)\(x|y\),其实以二进制的角度来看,就是这两个数的对应位上的 \(1\) 发生了转移,但是总共的 \(1\) 的个数未变,题目要求 \(a_i^2\),则 \(a_i\) 应该越大对答案的贡献才会越大,所以存下每个数对应位上的 \(1\) 有多少个,贪心地去凑出最大的数即可。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector<i64> a(n + 1), cnt(30);for (int i = 1; i <= n; i ++) {cin >> a[i];for (int j = 0; j < 20; j ++) {if (a[i] >> j & 1)cnt[j] ++;}}i64 ans = 0;for (int i = 1; i <= n; i ++) {int x = 0;for (int j = 0; j < 20; j ++) {if (cnt[j]) {x += 1 << j;cnt[j] --;}}ans += 1ll * x * x;}cout << ans << '\n';return 0;
}

D - D

AtCoder - arc082_b

思路

\(p_i=i\) 时,那它和旁边的数交换一定可以使得两边的数都不等于其下标,所以遍历一遍,碰到 \(p_i=i\) 的直接和旁边的数交换一下记录答案即可。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector<int> p(n + 1);for (int i = 1; i <= n; i ++) {cin >> p[i];}int ans = 0;for (int i = 1; i <= n; i ++) {if (p[i] != i) continue;if (i + 1 <= n)swap(p[i], p[i + 1]);elseswap(p[i], p[i - 1]);ans ++;}cout << ans << '\n';return 0;
}

E - E

CodeForces - 794C

思路

一道细节题。

贪心的思路是排序后 \(a\)\(b\) 依次把最小字母和最大字母往前面填,但当 \(S_a>S_b\) 的时候,\(a,b\) 往前填反而会成全对方,所以这个时候得往后填。

写法不同对细节的处理有不同。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);string a, b;cin >> a >> b;sort(a.begin(), a.end());sort(b.begin(), b.end(), greater<>());int n = a.size();string ans1 = "", ans2 = "";while (a.size() > (n + 1) / 2) a.pop_back();while (b.size() > (n) / 2) b.pop_back();while (n--) {if (a[0] < b[0]) {ans1 += a[0];a.erase(a.begin());} else {ans2 += a.back();a.pop_back();}if (n) {if (a[0] < b[0]) {ans1 += b[0];b.erase(b.begin());} else {ans2 += b.back();b.pop_back();}n--;}}reverse(ans2.begin(), ans2.end());cout << ans1 + ans2 << '\n';return 0;
}

F - F

CodeForces - 1076E

思路

这几天有点魔怔了,看到子树 \((u,v)\) 对什么的老是想到树上启发式,唉,杭电害得。

\(x\) 子树中距离小于等于 \(k\) 的点全都加上一个值 \(x\),假设这棵树只有一条链,那很显然,答案其实就是做一个差分,然后跑一个前缀和。

现在是多条链,但是这多条链上的点都需要加上 \(x\),那么不妨将深度看成一个序列,在深度上进行差分,用 dfs 跑前缀和,这样就完成了树上差分以及区间求值的操作。

需要注意的是,因为一棵树有不同的子树,也就是有许多不同的链,在对当前子树做完差分的操作,回溯的时候要记得还原,否则会影响其他子树的答案。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector g(n + 1, vector<int>());for (int i = 1; i < n; i ++) {int u, v;cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}int m;cin >> m;vector Q(n + 1, vector<pair<int, int>>());while (m--) {int v, d, x;cin >> v >> d >> x;Q[v].emplace_back(d, x);}vector<i64> pre(n + 1), ans(n + 1);auto dfs = [&](auto && self, int u, int fa, int dep, i64 sum)->void{for (auto &[d, x] : Q[u]) {pre[dep] += x;int to = dep + d + 1;if (to <= n) {pre[to] -= x;}}sum += pre[dep];ans[u] = sum;for (auto v : g[u]) {if (v == fa) continue;self(self, v, u, dep + 1, sum);}for (auto &[d, x] : Q[u]) {pre[dep] -= x;int to = dep + d + 1;if (to <= n) {pre[to] += x;}}};dfs(dfs, 1, 0, 0, 0);for (int i = 1; i <= n; i ++)cout << ans[i] << " \n"[i == n];return 0;
}

G - G

CodeForces - 611D

思路

考虑 dp。

\(dp_{i,j}\) 表示以从 \(j\)\(i\) 构成的数字(以下称做\(num_{i,j}\))作为结尾的方案数。

image

\(L=i-j\) 表示为该数字的长度,那么显然,大于这个长度的一定不可能转移过来,而小于这个长度的字符串构成的数字也一定小于 \(num_{i,j}\),那么这一步得到的转移方程为:

\[dp_{i,j}+=\sum\limits_{k=j-L}^{j-1}dp_{j-1,k} \]

这一步可以用前缀和优化。

接下来就是考虑相等的情况,相等的情况下可以通过 \(LCP(\text{最长公共前缀})\)\(n^2\) 算法预处理,然后判断 \(lcp\) 后的第一位大小情况即可,也可以通过 \(Sam\) 算法等。

\[dp_{i,j}+=dp_{j-1,k-1}[num_{i,j}>num_{j-1,k-1}] \]

我这里采用的是 二分+Hash 的做法(也有倍增+Hash),会比 \(n^2\) 的做法多一个 \(log\),总复杂度 \(O(n^2logn)\)

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;struct Hash {using u64 = unsigned long long;u64 base = 13331;vector<u64> pow, hash;Hash(string &s) {int N = s.size();pow.resize(N + 1), hash.resize(N + 1);pow[0] = 1, hash[0] = 0;for (int i = 1; i < s.size(); i ++) {pow[i] = pow[i - 1] * base;hash[i] = hash[i - 1] * base + s[i];}}u64 get(int l, int r) {return hash[r] - hash[l - 1] * pow[r - l + 1];}//拼接两个子串u64 link(int l1, int r1, int l2, int r2) {return get(l1, r1) * pow[r2 - l2 + 1] + get(l2, r2);}bool same(int l1, int r1, int l2, int r2) {return get(l1, r1) == get(l2, r2);}};int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;string s;cin >> s;s = " " + s;Hash hash(s);auto check = [&](int x, int y)->bool{int l = 0, r = y - x, ans = 0;while (l <= r) {int mid = l + r >> 1;if (hash.same(x, x + mid - 1, y, y + mid - 1)) l = mid + 1, ans = mid;else r = mid - 1;}if (ans == y - x) return false;return s[ans + x] < s[ans + y];};vector dp(n + 1, vector<i64>(n + 1));vector sum(n + 1, vector<i64>(n + 1));for (int i = 1; i <= n; i ++)dp[i][1] = 1;const i64 mod = 1e9 + 7;for (int i = 1; i <= n; i ++) {for (int j = 1; j <= i; j ++) {if (s[j] == '0') continue;int k = max(1, j - (i - j));(dp[i][j] += (sum[j - 1][j - 1] - sum[j - 1][k - 1] + mod) % mod) %= mod;k --;if (k >= 1 && check(k, j)) {(dp[i][j] += dp[j - 1][k]) %= mod;}}for (int j = 1; j <= i; j ++)sum[i][j] = (sum[i][j - 1] + dp[i][j]) % mod;}i64 ans = 0;for (int i = 1; i <= n; i ++)ans = (ans + dp[n][i]) % mod;cout << ans << '\n';return 0;
}

H - H

CodeForces - 1416B

思路

要获得均分首先得保证 \(Sum_a\bmod n=0\)

考虑一种做法就是,首先将所有的数都汇集到 \(a_1\) 上,然后其他数就是 \(0\) 了,然后由 \(a_1\) 统一分配 \(Avg\) 平均数给其他 \(n-1\) 个数,这样的做法有 \(2\times (n-1)\) 次操作。

期间会有一些数会产生余数,那么不妨让 \(a_1\) ‘借’点数给它使得被 \(i\) 整除,然后又一并还给 \(a_1\),题目保证 \(1\le a_i\le 1e5\),所以最开始一定有 \(1\) 去弥补 \(i=2\) 的余数,然后 \(a_2\) 把所有数给 \(a_1\) 后,又能保证有一定的数弥补 \(i=3 \dots\) 这样的操作最多也就 \((n-1)\) 次,所以总次数不会超过 \(3(n-1)\),满足题目要求。

代码

#include <bits/stdc++.h>using namespace std;using i64 = long long;void solve() {int n;cin >> n;i64 sum = 0;vector<int> a(n + 1);for (int i = 1; i <= n; i ++) {cin >> a[i];sum += a[i];}if (sum % n != 0) {cout << -1 << '\n';return ;}int avg = sum / n;vector<array<int, 3>> ans;for (int i = 2; i <= n; i ++) {int x;if (a[i] % i != 0) {x = i - a[i] % i;a[1] -= x;a[i] += x;ans.push_back({1, i, x});}x = a[i] / i;a[1] += a[i];a[i] = 0;ans.push_back({i, 1, x});}for (int i = 2; i <= n; i ++) {ans.push_back({1, i, avg - a[i]});}cout << ans.size() << '\n';for (auto [a, b, c] : ans) {cout << a << ' ' << b << ' ' << c << '\n';}}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int t;cin >> t;while (t--) {solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/777466.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 2189. Number of Ways to Build House of Cards

原题链接在这里:https://leetcode.com/problems/number-of-ways-to-build-house-of-cards/description/ 题目: You are given an integer n representing the number of playing cards you have. A house of cards meets the following conditions:A house of cards consists…

全网最适合入门的面向对象编程教程:31 Python的内置数据类型-对象Object和类型Type

Python 中的对象和类型是一个非常重要的概念。在 Python 中,一切都是对象,包括数字、字符串、列表等,每个对象都有自己的类型。全网最适合入门的面向对象编程教程:31 Python 的内置数据类型-对象 Object 和类型 Type摘要: Python 中的对象和类型是一个非常重要的概念。在 Pyt…

Golang语言goroutine协程并发安全及锁机制

作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任。 目录一.多协程操作同一数据问题引出二.互斥锁Mutex1 互斥锁概述2使用互斥锁Mutex同步协程三.读写互斥锁RWMutex1 读写互斥锁概述2 读写锁RWMutex引入 一.多协程操作同一数据问题引出package mainimport (&quo…

[rCore学习笔记 021]多道程序与分时任务

写在前面 本随笔是非常菜的菜鸡写的。如有问题请及时提出。 可以联系:1160712160@qq.com GitHhub:https://github.com/WindDevil (目前啥也没有 导读 这里就是第三章的开头了,由于我的巨菜,导致天天半天理解不了关键点所在,唉,实在是太折磨人. 遵照上一章开头的时候的优良传…

基于FPGA的2FSK调制解调系统,包含testbench,高斯信道模块,误码率统计模块,可以设置不同SNR

1.算法仿真效果本系统在以前写过的FSK调制解调系统的基础上,增加了高斯信道模块,误码率统计模块,可以验证不同SNR情况下的FSK误码情况。vivado2019.2仿真结果如下(完整代码运行后无水印):SNR=16dbSNR=10dbSNR=5dbSNR=0dbRTL结构图如下:2.算法涉及理论知识概要频移键控是…

Contest5400 - 网络流-1

RTContest A 签到题 B 最大流 Dinic 板子。 Dinic 的整体结构: ll dinic() {ll ans = 0;while (bfs()) { // 如果 s 还有能到 t 的增广路fill(cur+1, cur+n+1, 0); // 当前弧优化的预处理,暂时不用管ans += dfs(s, INF); // 多路增广}return ans; }BFS 建分层图: bool bfs()…

MySQL45讲基础篇

基础篇 01 | 基础架构:一条SQL查询语句是如何执行的? 你好,我是林晓斌。 这是专栏的第一篇文章,我想来跟你聊聊 MySQL的基础架构。我们经常说,看一个事儿千万不要直接陷入细节里,你应该先鸟瞰其全貌,这样能够帮助你从高维度理解问题。同样,对于MySQL的学习也是这样。平…

Datawhale AI 暑期夏令营 第四期Task3

Transformer架构 Transformer是一种用于自然语言处理(NLP)和其他序列到序列(sequence-to-sequence)任务的深度学习模型架构,它在2017年由Vaswani等人首次提出。Transformer架构引入了自注意力机制(self-attention mechanism),这是一个关键的创新,使其在处理序列数据时…

基于IEEE802.11g标准的OFDM信号帧检测matlab仿真

1.程序功能描述现有的无线通信信道共享的无线信号识别为将来的软件定义的无线电系统是一个巨大的挑战。在这个项目中,学生将制定IEEE802.11无线信号在AWGN信道,利用MATLAB/ Simulink技术来识别。一个完整的发射机模式将开发和实施。 在AWGN信道下的性能进行评估。基于IEEE802…

羽毛球比赛积分系统03

羽毛球比赛积分系统 1、产品愿景目标用户 学校的体育工作人员(老师、教练、裁判),学生和教师选手,赛事组织者,志愿者等羽毛球比赛的参与者。他们的需要或机会简化赛事安排和管理。 提高比赛的公正性和透明度。 实时掌握比赛成绩和排名。 增强赛事互动和参与体验。产品名称…