2025.1.8 练习赛总结

news/2025/1/8 20:43:27/文章来源:https://www.cnblogs.com/ny-Dacong/p/18660531

总览

本文同步发表与:

  • 洛谷:https://www.luogu.com.cn/article/hdzdhnif。
  • 博客园:<>。

打得不好,在赛时只做了 A 题。昨晚的睡眠使我刚好处于困和不困的叠加态,导致想题的时候脑子极乱。

A:Gym 103430F。

B:CF 578B。

C:CF 1407D。

D:洛谷 P11122。

E:CF 1208D。

A - Gym 103430F - X-Magic Pair

签到题。

设两数为 \(a,b\),默认 \(a > b\)(小于就 swap)。

那么差就是 \(a-b\)。考虑用 \(a-b\) 代替 \(b\),那么就变为 \(a,a-b\),这两个数相减之后就又变成了 \(a,b\)。是无用功。

所以用 \(a-b\) 代替 \(a\)。此时两数变为 \(a-b,b\)

如果 \(a-b < b\),那么 swap,重新定义 \(a,b\),重复上面的讨论。

如果 \(a-b > b\),那么接着相减就变为 \(a-2b\)。用 \(a-2b\) 代替 \(a-b\),接着讨论……

你会发现,这个操作实际上就是不断让 \(a-b\),直到 \(a < b\) 之后交换。

因此这个操作相当于 \(a \gets a \bmod b\),然后交换二者。

那么最终答案判定怎么判?当 \(b \le x \le a\) 时,看 \(a\) 能否减去若干个 \(b\) 使得 \(a = x\)

也就是说,是否存在一个正整数 \(k\),使得 \(a-kb = x\)。化简得 \(k = \frac{a-x}{b}\)

只要右边那一坨是正整数就有解。

上面默认 \(a \not = b\)。如果等于,要特判,不然会死循环。

#include<bits/stdc++.h>
using namespace std;
long long t;
long long a,b,x;
int main(){scanf("%lld",&t);while(t--){scanf("%lld%lld%lld",&a,&b,&x);if(a < b){swap(a,b);}if(x > a){puts("NO");continue;}while(!(b <= x && x <= a)){a -= ((a-1)/b)*b;if(a < b){swap(a,b);}if(a == b){break;}}if(x == a || x == b || (a-x)%b == 0){puts("YES");}else{puts("NO");}}return 0;
}
/*
Traveling in the nights you've left me in.
I feel you in the last blow of wind.
Even nowhere I can find you out.
The answer is not far off now.This journey of ours has been bittersweet.
Close my eyes wondering what you would have dreamed.
If you were here standing next to me,
Would you know, how I feel,
And see what I see?Know that I'll always try.
Finding you rhythm and rhyme.
Though the nights are long and dark, I'll see you shining bright.
And no matter where you are, you'll come with me this far.
Showing the way when all else falls apart~
*/

B - Codeforces 578B - "Or" Game

考场上一眼看上去是 DP,但是或运算不满足最优子结构特征,也就是局部最优解不等于全局最优解。因此 DP 假了。

实际上是贪心。这 \(k\) 次乘法一定要用在一个数身上。因为是或,所以要让有效位数尽可能多。又因为 \(x \ge 2\),所以实际上每次乘法都会向右至少移 1 位。所以你肯定得搁一个数往右移。

所以 \(O(n)\) 遍历每个数,枚举如果这个数乘 \(k\)\(x\) 之后,总答案是多少,最后取 \(\max\)。具体计算时可以用前缀和思想,维护前缀或与后缀或即可。

#include<bits/stdc++.h>
using namespace std;
long long n,m,k,ans = 0;
long long num[200050];
long long f[200050],b[200050];
long long slowpow(long long x,long long y){long long res = x;while(y--){res *= k;}return res;
}
int main(){scanf("%lld%lld%lld",&n,&m,&k);for(long long i = 1; i <= n; i++){scanf("%lld",&num[i]);f[i] = num[i]|f[i-1];}for(long long i = n; i >= 1; i--){b[i] = num[i]|b[i+1];}for(long long i = 1; i <= n; i++){ans = max(ans,f[i-1]|b[i+1]|slowpow(num[i],m));}printf("%lld",ans);return 0;
}

C - Codeforces 1407D - Discrete Centrifugal Jumps

既然连 WYR 小朋友都做出来了,我怎么不会做呢……

考场上脑子极乱,思路都是一样的,但是脑抽了。

具体的,我想:“设在 \(i\) 之前且第一个比 \(i\) 高的楼是 \(j\)”,然后想了半天又想:“万一有楼在 \(i \sim j\) 之间且比 \(i\) 高比 \(j\) 低呢……”

可见我是智障。


考虑朴素 DP。设 \(dp_i\) 为到第 \(i\) 号楼的最少步数。初始化 \(dp_1 \gets 0\),其余全部为 \(\infty\)

那么转移就是题目中描述的那样,分三种情况转移。

暴力代码:

memset(dp,0x3f,sizeof(int)*(n+10));
dp[1] = 0;
for(int i = 2; i <= n; i++){static int Min,Max;Min = inf,Max = -inf;dp[i] = dp[i-1]+1;for(int j = i-1; j >= 1; j--){if(max(num[i],num[j]) < Min){dp[i] = min(dp[i],dp[j]+1);}if(min(num[i],num[j]) > Max){dp[i] = min(dp[i],dp[j]+1);}Min = min(Min,num[j]);Max = max(Max,num[j]);}
}

先考虑 \(\max{h_{i+1},h_{i+2},\dots,h_{j-1}} < \min{h_i,h_j}\) 的情况。另一种情况一样。

考虑一个 \(j\),如果 \(\max{h_{i+1},h_{i+2},\dots,h_{j-1}} > \min{h_i,h_j}\),这个 \(j\) 就失去了贡献资格。最后有资格的 \(j\) 按照坐标排下来一定是严格单调下降的。

手玩一下就会发现这个过程跟单调栈一模一样。当一个新元素有贡献资格时,原本可以贡献的,但是高度小于等于它的元素就失去了资格。这跟弹出栈顶的操作是同一个思想。

而这些弹出的元素都可以向准备加入的元素转移。同时第一个高度大于等于它的元素也可以向它转移。

所以维护一个单调栈,栈内存有资格贡献的元素,然后维护单调下降 / 单调上升的元素集合即可。

#include<bits/stdc++.h>
using namespace std;
long long n;
long long num[300050],dp[300050];
stack<long long> Max,Min;
int main(){scanf("%lld",&n);for(long long i = 1; i <= n; i++){scanf("%lld",&num[i]);}memset(dp,0x3f,sizeof(long long)*(n+10));dp[1] = 0;Max.push(1),Min.push(1);for(long long i = 2; i <= n; i++){dp[i] = dp[i-1]+1;while(Max.size() && num[i] >= num[Max.top()]){if(num[i] != num[Max.top()] && (int)Max.size() > 1){Max.pop();dp[i] = min(dp[i],dp[Max.top()]+1);}else{Max.pop();}}Max.push(i);while(Min.size() && num[i] <= num[Min.top()]){if(num[i] != num[Min.top()] && (int)Min.size() > 1){Min.pop();dp[i] = min(dp[i],dp[Min.top()]+1);}else{Min.pop();}}Min.push(i);}printf("%lld",dp[n]);return 0;
}

D - 洛谷 P11122 - 表格游戏

折半搜索,新知识。

发现删除顺序与最终答案无关。

考虑暴力。用状压表示删除情况。枚举删哪几行,然后枚举删哪几列。最坏情况两者各有 \(2^{15}\) 种情况,总复杂度为 \(O(2^{h+w})\)

考虑折半搜索。这个算法的思想为把搜索区间分成两半,每一半单独搜索,然后用高效的方法合并结果。

对于这道题,我们可以先枚举删哪几行,然后先枚举只删 \(1 \sim \lfloor \frac{w}{2} \rfloor\) 列的情况,再枚举只删 \(\lceil \frac{w}{2} \rceil \sim w\) 列的情况。最后合并二者的结果,判断是否有解。

这个方法优化了时间复杂度,从 \(O(2^{h+w})\) 优化到了 \(O(2^{h+ \frac{w}{2}})\)。可过。

#include<bits/stdc++.h>
using namespace std;
long long n,m,q;
long long num[20][20],sum[20];
long long state1;
unordered_map<long long,long long> state2;
vector<pair<long long,long long>> ans;
void dfs1(long long now,long long state,long long add){if(now == (m>>1)+1){state2[add] = state;return;}dfs1(now+1,state,add);dfs1(now+1,state|(1<<(now-1)),add+sum[now]);return;
}
void dfs2(long long now,long long state,long long add){if(now == m>>1){if(state2.count(q-add)){puts("YES");for(long long i = 0; i < n; i++){if(state1&(1<<i)){ans.push_back({1,i+1});}}for(long long i = 0; i < m; i++){if(!(state2[q-add]&(1<<i)) && !(state&(1<<i))){ans.push_back({2,i+1});}}printf("%lld\n",(long long)ans.size());for(auto i:ans){printf("%lld %lld\n",i.first,i.second);}exit(0);}return;}dfs2(now-1,state,add);dfs2(now-1,state|(1<<(now-1)),add+sum[now]);
}
int main(){scanf("%lld%lld",&n,&m);for(long long i = 1; i <= n; i++){for(long long j = 1; j <= m; j++){scanf("%lld",&num[i][j]);}}scanf("%lld",&q);for(long long i = 0; i < (1<<n); i++){for(long long j = 1; j <= m; j++){sum[j] = 0;for(long long k = 1; k <= n; k++){if(!(i&(1<<(k-1)))){sum[j] += num[k][j];}}}state1 = i;state2.clear();dfs1(1,0,0);dfs2(m,0,0);}puts("NO");return 0;
}

E - Codeforces 1208D - Restore Permutation

没想到最后一题反而更简单。可惜啊,没看。

首先,最后一个 \(0\) 一定是 \(1\)。因为在它前面没有比它更小的数了,而它后面的所有数都有比自身更小的数。

那么 \(1\) 的位置确定,不妨设其位置为 \(i\)。那么 \(1\) 会对 \(i+1 \sim n\) 的所有数产生贡献。所以把 \(i+1 \sim n\) 的所有数减去 \(1\),然后删掉 \(i\) 位置的这个数。

然后讨论 \(2\)。跟 \(1\) 的思路一样,讨论完 \(1\) 之后,最后一个 \(0\) 就是 \(2\)。以此类推。

所以我们需要一个可区间修改,区间查询最小值的数据结构。

太好了,是线段树,我们有救了!

至于如何知道最后一个 \(0\) 的具体下标,可以用二分。所以复杂度应该是双 \(\log\)

至于如何删掉这个数,其实不用真的删,赋值为 \(\infty\) 即可。

注意开 long long,而且 0x3f3f3f3f 不够用。

#include<bits/stdc++.h>
using namespace std;
const long long inf = 0x3f3f3f3f3f3f3f3f;
long long n;
long long num[200050],ans[200050];
long long tree[200050<<2],tag[200050<<2];
long long ls(long long x){return x<<1;
}
long long rs(long long x){return x<<1|1;
}
void push_up(long long p){tree[p] = min(tree[ls(p)],tree[rs(p)]);return;
}
void build(long long p,long long pl,long long pr){tree[p] = inf,tag[p] = 0;if(pl == pr){tree[p] = num[pl];return;}long long mid = pl+((pr-pl)>>1);build(ls(p),pl,mid);build(rs(p),mid+1,pr);push_up(p);return;
}
void addtag(long long p,long long opt){tree[p] -= opt;tag[p] += opt;return;
}
void push_down(long long p){if(tag[p]){addtag(ls(p),tag[p]);addtag(rs(p),tag[p]);tag[p] = 0;}return;
}
void modify(long long p,long long pl,long long pr,long long l,long long r,long long opt){if(l <= pl && pr <= r){addtag(p,opt);return;}long long mid = pl+((pr-pl)>>1);push_down(p);if(l <= mid){modify(ls(p),pl,mid,l,r,opt);}if(mid < r){modify(rs(p),mid+1,pr,l,r,opt);}push_up(p);return;
}
long long query(long long p,long long pl,long long pr,long long l,long long r){if(l <= pl && pr <= r){return tree[p];}long long mid = pl+((pr-pl)>>1),res = inf;push_down(p);if(l <= mid){res = min(res,query(ls(p),pl,mid,l,r));}if(mid < r){res = min(res,query(rs(p),mid+1,pr,l,r));}return res;
}
int main(){scanf("%lld",&n);for(long long i = 1; i <= n; i++){scanf("%lld",&num[i]);}build(1,1,n);for(long long i = 1; i <= n; i++){static long long l,r,mid,tp;l = 1,r = n;while(l <= r){mid = l+((r-l)>>1);if(query(1,1,n,mid,n) == 0){tp = mid;l = mid+1;}else{r = mid-1;}}ans[tp] = i;modify(1,1,n,tp,tp,-inf);modify(1,1,n,tp+1,n,i);}for(long long i = 1; i <= n; i++){printf("%lld ",ans[i]);}return 0;
}

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

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

相关文章

mongodb windows zip安装并服务自启动

1.下载并解压。2.新建文件/文件夹 data/db 目录 logs/mongod.log 文件 conf/mongod.conf 文件 3.编辑conf/mongod.conf文件 systemLog:destination: filelogAppend: truepath: F:/mongodb-win32-x86_64-windows-6.0.20-rc3/logs/mongod.logstorage:dbPath: F:/mongodb-win32-x…

Linux通过端口找到对应的服务

首先执行netstat -tulnp | grep <端口号>例如:netstat -tulnp | grep :80参数解释:-t: 显示 TCP 连接(只显示TCP协议的端口信息)。 -u: 显示 UDP 连接(只显示UDP协议的端口信息)。 -l: 显示正在监听(Listening)状态的端口(只显示处于监听状态的端口)。 -n: 以数…

2025新春源码免费送

我们常常在日常生活中感到时间过得异常缓慢,仿佛未来遥不可及。然而,当我们回过头去审视过去,才发现时间早已悄然溜走,许多曾经等待的日子已经过去。时间总是在不经意间流逝,让人意识到它的宝贵和不可逆转。 尽管如此,我们依然应对未来保持从容的态度。生活充满了无数的可…

2025.1.8 鲜花

Nim 的变种Nim 的变种グランドエスケープ 空飛ぶ羽根と引き換えに 繋ぎ合う手を選んだ僕ら 没有选择飞翔的翅膀 而是选择十指相扣的我们 それでも空に魅せられて 夢を重ねるのは罪か 却仍然向往着天空 反复做着同样的梦 这有错吗 夏は秋の背中を見て その顔を思い浮かべる 夏…

CTF 之 Crypto (Cryptography) 学习笔记

CTF 之 Crypto (Cryptography) Chapter 0. 前置知识 群 (Group) 给定一个集合 \(G\neq \emptyset\) 以及二元代数运算 \(\circ\),若满足:封闭性 (Closure):\(\forall u,v\in G\),\(u\circ v\in G\); 结合律 (Associativity):\(\forall u,v,w\in G\),\((u\circ v)\circ w…

(2025自测有效!)全网最好的python配置教程【非常非常适合小白】

前几天我的电脑刚刚重装,把python重新配置了一下。 1.Python环境部署Python3 可应用于多平台包括 Windows、Linux 和 Mac OS X。 Python官网:https://www.python.org/ 进入官网在导航栏选择Dowmloads,选择所使用的系统(以Windows为例) 进入Windows下载页之后选择需要下载的…

写一个支持折叠、有缩进、代码高亮、离线的,方便部署的、易用的、优雅的json格式化查看工具(附html完整代码)

缘由 网上的在线json格式化有很多,但我是个有追求的人。在线的很难同时支持折叠、有缩进线、代码高亮、离线的,方便部署的、易用的、不请求后端(为了安全)的json格式化工具。 去Github上找项目,华而不实的东西占半个屏幕,格式化json要点好几下,一个json格式化工具npm安装…

AGC041F Histogram Rooks

我不知道啊,我只是觉得容斥很好玩。一个朴素的想法是容斥:考虑钦定 \(S\) 集合的位置没有被车覆盖,则答案是 \((-1)^{|S|}2^{c}\),其中 \(c\) 是可以放车的位置,可以直接 dp 做到 \(\mathrm{O}(2^n \text{poly}(n))\),但是难以优化。 延续容斥的想法,注意到钦定一个位置…

rust学习十六.1、并发-乱弹和一个简单并发例子

如书本作者所言,并发编程在绝大部分语言中,都是相对复杂和困难的。 所以,涉及的内容会相对多一些,所涵盖的内容绝对不是几篇文章所可以容纳的。 权当一个乱弹琴! 和此系列的其它文章一样,本文的内容绝大部分来自于相关书籍,本人做了一些摘裁的工作,取我所需!一、无畏并…

解决jenkins git 拉取代码超时问题

jenkins默认的是时间是10分钟,在git fetch时候超过10分钟了就报错失败了,可在项目源码管理 新增 advance clone behaviours

Java Bluetooth 蓝牙通讯 BlueCove 扫描附近的蓝牙设备

目录BlueCove项目概述BlueCove API架构API的设计原则和实现方式关键类和方法的功能描述测试代码获取本机(PC)蓝牙扫描蓝牙 BlueCove项目概述 BlueCove是一个开源的蓝牙协议栈实现,旨在为Java开发者提供一个全面的、易于使用的API,从而在应用程序中实现蓝牙功能。该项目支持多…