Codeforces Round 993 (Div. 4)题解
Codeforces Round 993 (Div. 4)
现在div4出那么难干嘛...
A. Easy Problem
输入一个数n,返回有多少组正整数(a,b) 满足
。
每个数可以选择[1,n-1]共计n-1对。
void solve()
{
int n = 0;
cin >> n;
cout << n - 1 << endl;
}
玻璃上正面写一串pqw组成的字符串,输出背面看过去的字符串
翻转字符串,然后还要把pq对应替换
void solve()
{
string s;
cin >> s;
reverse(s.begin(), s.end());
for (auto& v : s) {
if (v == 'p') v = 'q';
else if (v == 'q') v = 'p';
}
cout << s << endl;
}
有两排m个座位安排给猴子坐,a个猴子只能坐第一排,b个猴子只能做第二排,c个猴子都可以。问最多安排多少个猴子坐下
贪心 第一排坐 min(m,a)个,第二排坐min(m,b)个,然后剩下的尽量放c
void solve()
{
int m, a, b, c;
cin >> m >> a >> b >> c;
int c1 = min(m, a);
int c2 = min(m, b);
int c3 = min(m - c1 + m - c2, c);
cout << c1 + c2 + c3 << endl;
}
给定长度为n的数组A,
,要求构建数组B,满足每个 是区间 的众数(或之一)
比如A=[1,1,2],则B可以是[1,2,2]
由于只要满足是众数之一即可,显然可以构建B为一个n的排列即可,每个数字出现次数都是1,只需要在
处理时要做到,每个
那么可以在每个数字v首次出现的位置直接标记
然后从头遍历ans中为标记的位置,另一个指针就从1开始累加,找到第一个flag[v]为标记的数字赋值即可。
void solve()
{
int n; cin >> n;
vector<int> flag(n + 1);
vector<int> ans(n);
for (int i = 0; i < n; i++) {
int v; cin >> v;
if (!flag[v]) {
flag[v] = 1;
ans[i] = v;
}
}
int now = 1;
for (int i = 0; i < n; i++) {
if (ans[i] == 0) {
while (flag[now]) now++;
ans[i] = now++;
}
}
for (int i = 0; i < n; i++) cout << ans[i] << " ";
cout << endl;
}
给定
,要求统计 数对个数,要求满足
这条意思是 是k的某个幂。比如k=2,y=8,x=2,则 ,注意 必须是整除
这里n可以为0,考虑n=0的情况,此时
求重叠区间有个常识做法,即重叠部分区间设为[L,R],则有
如果
由于n为指数,可以暴力枚举n∈[0,60],对于n>0的情况,考虑x的值域,类似地,有
设
void solve()
{
long k, x1, x2, y1, y2;
cin >> k >> x1 >> x2 >> y1 >> y2;
long ans = 0;
for (int n = 0; n <= 60; n++) {
long r = pow(k, n);
if (r * x1 > y2) break;
ans += max(0L, min(x2, y2 / r) - max(x1, (y1 + r - 1) / r) + 1);
}
cout << ans << endl;
}
给定n长度数组A,m长度数组B,n*m矩阵的每一项为
,设矩阵元素和为 。
你可以在一次操作中,可以将M某一行和某一列同时设置为0。
有q次查询,每次查询给出一个整数,问能否通过一次操作使得矩阵元素和 ,每次查询独立。
1<=n,m,x<=2e5
认真思考这个数据范围,n,m均为2e5,且没有标准n*m的范围,说明实际上无法枚举整个矩阵。只能单独枚举AB数组。
而x<=2e5,启发我们通过x的值处理。
在无操作的时候有
请务必意识到这是一个将整数
具体来说,预处理所有的
分解
注意
unordered_set会被卡哈希,不行就数组吧,或者自定义哈希函数。
void solve()
{
i64 n, m, q; cin >> n >> m >> q;
i64 sumA = 0, sumB = 0;
vector<i64> A(n);
for (int i = 0; i < n; i++) cin >> A[i], sumA += A[i];
vector<i64> B(m);
for (int i = 0; i < m; i++) cin >> B[i], sumB += B[i];
set<i64> setA, setB;
for (int i = 0; i < n; i++) setA.insert(sumA - A[i]);
for (int i = 0; i < m; i++) setB.insert(sumB - B[i]);
auto dfs = [&](i64 x) -> bool {
if (x == 0) {
if (setA.count(0) || setB.count(0)) return true;
}
i64 y = abs(x);
for (int i = 1; i <= y / i; i++) {
if (y % i == 0) {
if (setA.count(i) && setB.count(x / i)) return true;
if (setA.count(-i) && setB.count(-x / i)) return true;
if (setB.count(i) && setA.count(x / i)) return true;
if (setB.count(-i) && setA.count(-x / i)) return true;
}
}
return false;
};
while (q-- > 0) {
i64 x; cin >> x;
if (dfs(x)) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
G1. Medium Demon Problem (easy version)
给定长为n的数组,每个元素
表示有一条从 的有向边,初始每个节点拥有一个礼物,每一轮每个节点会向子节点派发这个礼物。如果某个节点拥有超过1个,会立即变为1个。所有的派发同时发生。
问最少经过多少轮,所有节点的礼物数不再发生变化。
翻译完其实是很明显的内向基环树
然后求的是不在环上的点,距离环的最远距离。普通模拟大致是求出所有环上节点,然后倒序BFS查找最远距离。
第一轮是初始状态,经过最远的链的长度轮数后,到达环上,然后下一轮开始循环。
还是给个简易示意图。如下,节点9的礼物经过最多轮数到达环上,9->8->7->1,所以答案是3+2=5。
更简洁的做法是拓扑排序计算拓扑轮数即可。
特别注意,环上延伸出来的并非是一定是链,也可能是树,注意始终取子树里的最长链
void solve()
{
int n; cin >> n;
vector<int> deg(n);
vector<int> fa(n);
for (int u = 0; u < n; u++) {
int v; cin >> v;
v--;
deg[v]++;
fa[u] = v;
}
int step = 2;
queue<int> queue;
for (int i = 0; i < n; i++) if (deg[i] == 0) queue.push(i);
while (queue.size() > 0) {
int size = queue.size();
while (size-- > 0) {
int u = queue.front();
queue.pop();
int v = fa[u];
deg[v]--;
if (deg[v] == 0) queue.push(v);
}
step++;
}
cout << step << endl;
}
G2. Medium Demon Problem (hard version)
与G1的区别在于 过程中节点个数可以>1,而每次只能向上派发一个,所以需要把当前节点所有子树下的礼物逐个派发完成才行
所以向上返回时需要附加当前子树size。
void solve()
{
int n; cin >> n;
vector<int> deg(n);
vector<int> fa(n);
for (int u = 0; u < n; u++) {
int v; cin >> v;
v--;
deg[v]++;
fa[u] = v;
}
queue<int> queue;
vector<int> gifts(n);
for (int i = 0; i < n; i++) {
if (deg[i] == 0) queue.push(i);
gifts[i] = 1;
}
int ans = 0;
while (queue.size() > 0) {
int size = queue.size();
while (size-- > 0) {
int u = queue.front();
ans = max(ans, gifts[u]);
queue.pop();
int v = fa[u];
deg[v]--;
gifts[v] += gifts[u];
if (deg[v] == 0) queue.push(v);
}
}
cout << ans + 2 << endl;
}
基环树只有一个环
拓扑排序的处理过程中 依然可以计算子树size并向上返回,但是处理顺序是拓扑排序的顺序。
给定n行m列的矩阵,q个查询,每个查询里选择矩阵里的子区域,[x1,x2,y1,y2],然后把子区域扁平化为一个数组A
可知数组长度为
计算
此处必须附上出题人的灵魂画图:
这很Educational啊,先从一维去理解,给定长为n的数组A
从中任取区间[L,R],计算
比如数组[1,2,3,4,5,6],区间[L,R]=[3,5],截取的子数组为[3,4,5]
然后计算S=3 * 1 + 4 * 2 + 5 * 3 = 26。
当有q次查询时,我们如何快速的计算呢?
这是一个很好的公式推导教学
左侧是
计算区间和常用策略是前缀和
很自然地,我们设sumA表示数组前i项之和,设sumAi表示数组前i项与i的乘积和,则有
对于[3,4,5]的案例,等价的,
下面我们回到原题的二维情况
到这里我们得到了一个二维求和的公式,观察到为了计算S,我们需要预处理三个二维前缀和。分别是
对于每个二维前缀和 我们分别计算子区域的和 然后按公式相加即可。
下面贴完整代码
#include<bits/stdc++.h>
using namespace std;
using i64 = long long;
#define vi vector<i64>
#define vvi vector<vi>
void solve()
{
int n, q; cin >> n >> q;
vvi nums(n);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
i64 v; cin >> v;
nums[i].push_back(v);
}
}
vvi sum(n + 1, vi(n + 1)), sum_i(n + 1, vi(n + 1)), sum_j(n + 1, vi(n + 1));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
sum[i][j] += sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + nums[i - 1][j - 1];
sum_i[i][j] += sum_i[i - 1][j] + sum_i[i][j - 1] - sum_i[i - 1][j - 1] + nums[i - 1][j - 1] * i;
sum_j[i][j] += sum_j[i - 1][j] + sum_j[i][j - 1] - sum_j[i - 1][j - 1] + nums[i - 1][j - 1] * j;
}
}
auto sumRegion = [&](vvi& sum, int x1, int x2, int y1, int y2) -> i64 {
return sum[x2][y2] - sum[x1 - 1][y2] - sum[x2][y1 - 1] + sum[x1 - 1][y1 - 1];
};
vi ans;
while (q-- > 0) {
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
i64 s1 = sumRegion(sum_i, x1, x2, y1, y2) * (y2 - y1 + 1);
i64 s2 = sumRegion(sum, x1, x2, y1, y2) * (x1 * (y2 - y1 + 1) + y1 - 1);
i64 s3 = sumRegion(sum_j, x1, x2, y1, y2);
ans.push_back(s1 - s2 + s3);
}
for (auto v : ans) cout << v << " ";
cout << endl;
}
int main() {
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
cin >> t;
while (t-- > 0) {
solve();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具