当前位置: 首页 > news >正文

Codeforces Round 1086 (div.2) A~D2题解

A

题面

给定一个 \(n \times n\) 的网格, 每个格子有一个颜色值 \(a_{i,j}\). 问能否重排整个网格中的元素, 使得没有任何一行或一列的所有 \(n\) 个元素颜色相同.

\(\sum n \le 500\)
\(1 \le a_{i,j} \le n^2\)

解析

考虑最极端的情况, 我们可以构造出有 \(n \cdot (n - 1)\) 个相同颜色的网格而没有任何一行或一列的所有 \(n\) 个元素颜色相同, 但是对于有 \(n \cdot (n - 1) + 1\) 个相同颜色的网格由抽屉原理可以得到必定存在一行或一列的所有 \(n\) 个元素颜色相同, 因此只需要判断网格中是否有颜色的出现次数大于 \(n \cdot (n - 1)\).

时间复杂度 \(O(n^2)\).

代码

#include <bits/stdc++.h>
using namespace std;int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int t;cin >> t;while(t--){int n;cin >> n;vector <int> v(n * n + 11, 0);for(int i = 1; i <= n * n; i++){int x;cin >> x;v[x]++;}bool tag = 1;for(int i = 1; i <= n * n; i++)if(v[i] > n * (n - 1)){tag = 0;break;}cout << (tag ? "Yes\n" : "No\n");}return 0;
}

B

题面

\(n\) 张卡牌排成队列, 每次只能从前 \(k\) 张中选一张打出同时消耗对应能量, 然后将其移到队尾. 目标卡牌初始在第 \(p\) 位, 每张卡牌打一次消耗 \(a_i\) 能量, 总能量上限为 \(m\). 问在总花费不超过 \(m\) 的前提下, 最多能打出多少次目标卡牌.

\( \sum n \le 5000 \\ 1 \le k,p \le n \le 5000 \\ 1 \le m \le 5000 \\ 1 \le a_i \le m \)

解析

贪心加模拟即可.

代码

#include <bits/stdc++.h>
using namespace std;struct pii{int first, second;bool operator< (const pii y) const{return ((first == y.first) ? (second > y.second) : (first < y.first));}
};int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int tt;cin >> tt;while(tt--){int n, k, p, m;cin >> n >> k >> p >> m;priority_queue <pii> pq;queue <pii> q;for(int i = 1; i <= n; i++){int x;cin >> x;pii y;if(i == p)y = {1, x};else y = {0, x};if(i <= k)pq.push(y);elseq.push(y);}int ans = 0;while(m > 0){auto t = pq.top();pq.pop();if(t.second <= m){q.push(t);m -= t.second;pq.push(q.front());q.pop();if(t.first == 1)ans++;}else break;}cout << ans << '\n';}return 0;
}

C

题面

你有 \(n\) 个任务, 按顺序处理 (从 1 到 \(n\)). 初始体力 \(S = 1\). 对每个任务 \(i\), 可选:

  • 放弃: 无影响
  • 完成: 获得 \(S \cdot c_i\) 分, 但体力变为 \(S \cdot (1 - \frac{p_i}{100})\)

求最大化总得分.

\(\sum n \le 10^5\)
\(1 \le c_i \le 100\)
\(0 \le p_i \le 100\)

解析

按顺序完成任务获取积分损失体力, 比较典型的动态规划问题. 注意到每次获取的积分和损失的体力都是按比例缩放的, 因此无论当前的体力 \(S\) 是多少, 后续任务中得到的最大积分都是 \(S \times (当前体力为 \ 1 \ 时后续能得到的最大积分)\), 因此我们从后往前做 \(dp\).

\(dp[i]\) 表示如果在面临第 \(i\) 个任务时, 我们的体力值为 1, 那么从第 \(i\) 个任务到第 \(n\) 个任务最多可以得到的积分. 状态转移方程 \(dp[i] = \max(dp[i + 1], c[i] + (1 - \frac{p_i}{100}) \cdot dp[i + 1])\). 最后答案为 \(dp[1]\).

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

代码

#include <bits/stdc++.h>
using namespace std;int main(){int t;scanf("%d", &t);while(t--){int n;scanf("%d", &n);vector <int> c(n + 1), p(n + 1);for(int i = 1; i <= n; i++)scanf("%d %d", &c[i], &p[i]);vector <double> dp(n + 1, 0.0);dp[n] = 1.0 * c[n];for(int i = n - 1; i; i--)dp[i] = max(dp[i + 1], 1.0 * c[i] + (1.0 - 1.0 * p[i] / 100.0) * dp[i + 1]);printf("%.9lf\n", dp[1]);}return 0;
}

D1

题面

这是该问题的简单版本, 版本区别在 \(n\) 的大小.

给定一个 \(n\) 个节点的有向图的可达性矩阵 \(a_{i, j}\) (\(n \times n\) 的 0/1 字符串, 第 \(i\) 行第 \(j\) 列为 '1' 表示从 \(i\) 能到达 \(j\)), 问是否存在一棵无向树, 在对每条边定向后, 其可达关系恰好匹配该矩阵.

\(\sum n^3 \le 500^3\)
\(2 \le n \le 500\)

解析

我们关心的是两个点是否可以直接到达 (即这两个点在树中连有边), 不妨设 \(i\) 可以到达 \(j\), 即 \(a_{i, j} = 1\), 那么如果这两个点不是直接相连的, 那么就存在若干个中间点将 \(i\)\(j\) 连起来, 也就是存在点 \(k\), 使得 \(a_{i, k} = 1\)\(a_{k, j} = 1\), 因此我们得到了一个必要条件. 通过三次循环可以将所有满足这个条件的边选出来, 然后判断合法性即可.

时间复杂度 \(O(n^3)\).

代码

#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> pii;struct DSU{int n;vector <int> f;DSU(int _n) : n(_n){f = vector <int> (n + 1, 0);for(int i = 1; i <= n; i++)f[i] = i;}int find(int x){return (f[x] == x ? x : find(f[x]));}void join(int x, int y){int fx = find(x), fy = find(y);if(fx != fy) f[fx] = fy;}
};void solve(){int n;cin >> n;vector <vector <bool>> v(n + 1, vector <bool> (n + 1, 0));for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++){char c;cin >> c;v[i][j] = (c - '0');}for(int i = 1; i <= n; i++)if(!v[i][i]){cout << "No\n";return;}vector <pii> ans;for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(i != j && v[i][j]){bool tag = 1;for(int k = 1; k <= n; k++)if(k != i && k != j && v[i][k] && v[k][j]){tag = 0;break;}if(tag) ans.push_back({i, j});}if(ans.size() == n - 1){vector <vector <int>> to(n + 1);DSU dsu = DSU(n);for(auto [x, y] : ans){to[x].push_back(y);dsu.join(x, y);}int num = 0;for(int i = 1; i <= n; i++)if(dsu.f[i] == i) num++;if(num > 1){cout << "No\n";return;}for(int i = 1; i <= n; i++){queue <int> q;q.push(i);while(!q.empty()){int x = q.front();if(!v[i][x]){cout << "No\n";return;}// v[i][x] = 0;q.pop();for(auto l : to[x])q.push(l);}}// for(int i = 1; i <= n; i++)//     for(int j = 1; j <= n; j++)//         if(v[i][j]){//             cout << "No\n";//             return;//         }cout << "Yes\n";for(auto [x, y] : ans)cout << x << ' ' << y << '\n';}elsecout << "No\n";
}int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int t;cin >> t;while(t--) solve();return 0;
}

D2

题面

这是该问题的困难版本, 版本区别在 \(n\) 的大小.

给定一个 \(n\) 个节点的有向图的可达性矩阵 \(a_{i, j}\) (\(n \times n\) 的 0/1 字符串, 第 \(i\) 行第 \(j\) 列为 '1' 表示从 \(i\) 能到达 \(j\)), 问是否存在一棵无向树, 在对每条边定向后, 其可达关系恰好匹配该矩阵.

\(\sum n^2 \le 8000^3\)
\(2 \le n \le 8000\)

解析

很显然这个版本限制了复杂度最多在平方级别, 因此我们在 \(D1\) 的策略就不能用了, 但是我们的基本目标还是一样的, 就是找出直接相连的边.

考虑和 \(D1\) 中一样的情况: \(a_{i, j} = 1, a_{i, k} = 1, a_{k, j} = 1\), 设 \(s_i\) 表示 \(i\) 可以到达的点的个数, 那么有序关系 \(s_i > s_k > s_j\). 因此我们可以将数组 \(s\) 进行排序后从大到小的处理, 设排序后为 \(p\).

考虑节点 \(u\), 取空数组 \(vis\), 我们按照序列 \(p\) 枚举 \(u\) 可能的直接子节点 \(v\), 如果 \(v\) 不在 \(vis\) 中, 那么 \(v\) 就是 \(u\) 的一个直接子节点, 我们将 \(v\) 的所有可达点放到 \(vis\) 中. 原因是如果 \(v\) 不是 \(u\) 的直接子节点, 不妨设中间存在一个 \(u\) 的直接节点 \(w\), 那么有序关系 \(s_u > s_w > s_v\), 因此我们会先处理节点 \(w\), 此时 \(w\) 的所有可达点(其中包括节点 \(v\))都会被放入 \(vis\) 中, 与 \(v\) 不在 \(vis\) 中矛盾.

时间复杂度 \(O(n^2)\).

代码

#include <bits/stdc++.h>
using namespace std;
typedef pair <int, int> pii;struct DSU{int n;vector <int> f;DSU(int _n) : n(_n){f = vector <int> (n + 1, 0);for(int i = 1; i <= n; i++)f[i] = i;}int find(int x){return (f[x] == x ? x : find(f[x]));}void join(int x, int y){int fx = find(x), fy = find(y);if(fx != fy) f[fx] = fy;}
};void solve(){int n;cin >> n;vector <vector <bool>> v(n + 1, vector <bool> (n + 1, 0));vector <vector <int>> to(n + 1);vector <pii> num(n + 1, {0, 0});for(int i = 1; i <= n; i++){num[i].first = i;for(int j = 1; j <= n; j++){char c;cin >> c;v[i][j] = (c - '0');num[i].second += (c - '0');if(v[i][j])to[i].push_back(j);}}sort(num.begin() + 1, num.end(), [&](pii x, pii y){return x.second > y.second;});vector <int> vis(n + 1, 0);vector <pii> ans;int siz = 0;for(int i = 1; i <= n; i++){vis = vector <int> (n + 1, 0);int u = num[i].first;for(int j = i + 1; j <= n; j++){int w = num[j].first;if(v[u][w] && !vis[w]){ans.push_back({u, w});siz++;if(siz > n - 1)goto END;for(auto l : to[w])vis[l] = 1;}}}END:;// for(auto [x, y] : ans)//     cout << x << ' ' << y << '\n';if(siz == n - 1){vector <vector <int>> to(n + 1);DSU dsu = DSU(n);for(auto [x, y] : ans){to[x].push_back(y);dsu.join(x, y);}int num = 0;for(int i = 1; i <= n; i++)if(dsu.f[i] == i) num++;if(num > 1){cout << "No\n";return;}for(int i = 1; i <= n; i++){queue <int> q;q.push(i);while(!q.empty()){int x = q.front();if(!v[i][x]){cout << "No\n";return;}v[i][x] = 0;q.pop();for(auto l : to[x])q.push(l);}}for(int i = 1; i <= n; i++)for(int j = 1; j <= n; j++)if(v[i][j]){cout << "No\n";return;}cout << "Yes\n";for(auto [x, y] : ans)cout << x << ' ' << y << '\n';}elsecout << "No\n";
}int main(){ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);int t;cin >> t;while(t--) solve();return 0;
}
http://www.jsqmd.com/news/481597/

相关文章:

  • 探讨半亩酒店管理性价比,靠谱不,价格如何 - 工业设备
  • Python 异步编程完全指南(二):深入 asyncio 核心概念
  • 追觅俞浩:AI时代所有产品都值得重做一遍
  • 2026年黑龙江服务不错的公考培训专业公司,费用情况怎么样 - 工业品网
  • 龙虾退场全攻略:彻底清除OpenClaw残留
  • 格力“真AI爱”引爆AWE2026,打造人工智能与家居生活融合科技盛宴
  • 高端腕表维修养护进阶测评:故障精准排查+品牌适配升级指南 - 时光修表匠
  • 【独家原创未发表】基于差分进化算法(DE)优化Transformer结合双向长短期记忆神经网络 (BiLSTM)的数据回归预测附Matlab代码
  • 【数据分析】基于matlab的气候的疟疾传播模型,具备季节性最优控制和成本效益分析
  • [特殊字符] Python 自动化神器:10 分钟搞定 CSDN 批量发文
  • 【数据结构】最长连续递增子序列
  • 2026年热门储罐源头厂家有哪些?一文为你深度评测,埋地油罐/灰罐/立式不锈钢罐/粉煤灰罐/石灰罐,储罐工厂推荐 - 品牌推荐师
  • 【无人机控制】倾转旋翼 四旋翼无人机轨迹跟踪的 LMPC(线性模型预测控制)附matlab代码
  • 2026年辽宁异型铝单板厂家实力推荐:创意造型与精湛工艺的幕墙装饰解决方案专家 - 品牌企业推荐师(官方)
  • 多无人机动态避障路径规划:复杂三维山地环境下蚁群优化算法ACO求解多无人机动态避障路径规划研究附MATLAB代码
  • 基于冠豪猪优化算法优化径向基神经网络的数据分类预测附Matlab代码
  • SharePoint Online 文档库的还原功能
  • 防火墙的5大类型,分别适用于哪些场景?
  • CLIP:连接视觉与语言的桥梁 - 鹏展
  • std::chrono说自己是纳秒精度,但你的CPU可能不答应——从硬件时钟源到现代C++高精度计时器的设计真相
  • 探寻2026年高性价比征地拆迁律所,一讼律所口碑出众 - myqiye
  • 探寻2026年西北好用的桌椅精品定制,万匠酒店家具值得考虑 - 工业品牌热点
  • 20252807阙珂 2025-2026-2 《网络攻防实践》第1周作业
  • OpenClaw 怎么更新?三种方式 + 更新渠道完整指南(2026 年 3 月)
  • 开题卡住了?9个一键生成论文工具深度测评与推荐,研究生必备!
  • 2026年漳州地区水玻璃制造商推荐,水玻璃定制怎么选择 - mypinpai
  • 总结2026年配眼镜店价格与口碑,康视怡眼镜店名列前茅 - mypinpai
  • 2026年天津离婚案件律师对比评估 基于服务流程与口碑精准选择 - 速递信息
  • 聊聊贵州塑料工业厂房建设全案、高性价比工厂,怎么选择? - 工业推荐榜
  • 格式总出错?AI论文软件 千笔 VS 万方智搜AI,MBA写论文更高效!