jiejiejiang2004

题解:CF contest 2037 : [Codeforces Round 988 (Div. 3)] (A-E)

A Twice

题面

Kinich 醒来迎接新的一天的开始。他打开手机,查看邮箱,发现了一份神秘的礼物。他决定打开礼物的盒子。

Kinich 用 n 整数打开数组 a 。最初,Kinich的分数是 0 。他将执行任意次数的以下操作:

—选择两个索引 ij (1i<;jn) ,确保在之前的操作中没有选择 ijai=aj 。然后,将 1 加到他的分数上。

输出 Kinich 在执行上述操作任意次数后可以获得的最大分数。

题解

实际上我们不用管这个数组,我们只要把对出现次数大于 2 的数字进行记录处理就可以了

对每种出现次数大于 2 的数字,我们能操作 /2

最后对其求和即可

具体实现可以用 map ,因为范围不大,用数组存也可以。

代码

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define lowbit(x) x&-x
using i64 = long long;
using pii = std::pair<int,int>;
void solve() {
int n;
std::cin >> n;
int ans = 0;
std::map<int,int> mp;
for(int i = 0 ; i < n ; i ++) {
int num;
std::cin >> num;
mp[num] ++;
}
for(std::map<int,int>::iterator i = mp.begin() ; i != mp.end() ; i ++) {
ans += i->second / 2;
}
std::cout << ans << "\n";
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t = 1;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}

B Intercepted Inputs

题面

为了帮助您为即将到来的 Codeforces 竞赛做准备,Citlali设置了一个网格问题,并试图通过您的输入流为您提供一个 n×m 的网格。具体来说,你的输入流应该包含以下内容:

  • 第一行包含两个整数 nm —— 网格的尺寸。

  • 下面的 n 行包含 m 个整数 —— 网格的值。

然而,有人截获了你的输入流,打乱了所有给定的整数,并把它们都放在一行上!现在, k 整数都在一行中,并且您不知道每个整数最初属于哪里。您决定自己确定 nm 的值,而不是要求Citlali重新发送输入。

输出Citlali可能提供的 nm 的任何可能值。

题解

第一个数是 k 代表下列一行的长度

下面一行是数,包括矩阵的数字 以及 矩阵的长和宽

因此,矩阵的大小已经确定,即 n×m=k2

也就是说,我们只要在下面一行中找到能够构成 相乘的乘积等于 k2 的一对数即可(不管顺序)

  1. 最容易想到的暴力算法,时间复杂度为 O(n2) ,超时
  2. 我们可以在 O(n) 的时间复杂度内实现
    从前往后遍历,如果前面出现过能与当前数相乘得到 k2 的数,就可以直接输出
    具体存储结构可以用 map(不知道可不可以用数组)

代码

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define lowbit(x) x&-x
using i64 = long long;
using pii = std::pair<int,int>;
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for(int i = 0 ; i < n ; i ++) {
std::cin >> a[i];
}
std::map<int,int> mp;
int m = n - 2;
for(int i = 0 ; i < n ; i ++) {
if(m%a[i] == 0) {
if(mp.count(m/a[i])) {
std::cout << a[i] << " " << m / a[i] << "\n";
return;
}
}
mp[a[i]] ++;
}
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t = 1;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}

C Superultra's Favorite Permutation

题面

超级,一只小熊猫,拼命想要原始宝石。在他的梦中,一个声音告诉他,他必须解决以下任务,以获得一生的原始宝石供应。帮助Superultra !

构造一个长度为 n 的排列 p ,使得 pi+pi+1 是所有 1in1 的组合 。如果不可能,输出 1

长度为 n 的排列是一个由 1n 之间任意顺序的 n 不同整数组成的数组。例如, [2,3,1,5,4] 是一个排列,但 [1,2,2] 不是一个排列( 2 在数组中出现了两次), [1,3,4] 也不是一个排列( n=3 但数组中有 4 )。

如果一个整数 x 除了 1x 之外至少有一个除数,那么这个整数 x 就是合数。例如, 4 是合数,因为 2 是一个除数。

题解

已知:非 2 且 非 0 的 偶数一定是合数

已知:奇数和奇数相加是偶数(大于 2 ),偶数和偶数相加是偶数(大于 2 ),奇数和偶数相加是奇数

已知:最小的奇数合数是 9 ,可以由 45 相加得到

因此:

  • n<5 时,不可能构造成功,直接输出 1;

  • n5 时,把 54 放中间。其余奇数和偶数分别放两边,即构造成功

代码

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define lowbit(x) x&-x
using i64 = long long;
using pii = std::pair<int,int>;
void solve() {
int n;
std::cin >> n;
if(n < 5) {
std::cout << -1 << "\n";
return;
}
for(int i = 1 ; i <= n ; i += 2) {
if(i == 5) continue;
std::cout << i << " ";
}
std::cout << 5 << " " << 4 << " ";
for(int i = 2 ; i <= n ; i += 2) {
if(i == 4) continue;
std::cout << i << " ";
}
std::cout << "\n";
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t = 1;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}

D Sharky Surfing

题面

Mualani 喜欢在她的鲨鱼冲浪板上冲浪!

Mualani 的冲浪路径可以用数轴来表示。她从位置 1 开始,路径在位置 L 结束。当她在位置 x ,跳跃能力为 k 时,她可以跳到区间 [x,x+k] 内的任何位置。最初,她的跳跃功率为 1

然而,她的冲浪之路并非一帆风顺。在她的道路上有许多障碍。每个跨栏用区间 [l,r] 表示,这意味着她不能跳到区间 [l,r] 中的任何位置。

在路径上的某些位置也有能量提升。上电 i 位于 xi 位置,值为 vi 。当 Mualani 在位置 xi 时,她可以选择收集能量以增加她的跳跃能力 vi 。在同一个位置可能会有多个升级道具。当玩家处于拥有一些能量道具的位置时,他可能会选择接受或忽略每个能量道具。在任何障碍的间隔中都没有能量。

到达位置 L 完成路径,她必须收集的能量的最小数量是多少?如果无法完成冲浪路径,则输出 1

题解

这题是一道典型的贪心,他甚至给你排好序了!感动死了。

我们只需要一个优先队列去维护就可以了:

在一个障碍之前,把前面的道具 push 进队列,然后如果你的跳跃能力(以下简称 jump )不足以跳过时,就从队列里拿出来一个道具,加到 jump 里面

如果即使队列空了,这个 jump 还是不足以跳过去,那就直接输出 1 结束

如果全部都 ok 了,那就输出加了多少个道具。

(感觉还是有点不是很清晰,不懂的可以在评论区问)

代码

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define lowbit(x) x&-x
using i64 = long long;
using pii = std::pair<int,int>;
void solve() {
int n,m,l;
std::cin >> n >> m >> l;
std::vector<pii> str(n),power(m);
for(int i = 0 ; i < n ; i ++) {
std::cin >> str[i].first >> str[i].second;
}
for(int i = 0 ; i < m ; i ++) {
std::cin >> power[i].first >> power[i].second;
}
int ans = 0;
int jump = 1;
int idx = 0;
std::priority_queue<int> q;
for(int i = 0 ; i < n ; i ++) {
while(idx < m && power[idx].first < str[i].first) {
q.push(power[idx].second);
idx ++;
}
while(str[i].first - 1 + jump <= str[i].second && !q.empty()) {
jump += q.top();
q.pop();
ans ++;
}
if(str[i].first - 1 + jump <= str[i].second) {
std::cout << -1 << "\n";
return;
}
}
std::cout << ans << "\n";
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
int t = 1;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}

E Kachina's Favorite Binary String (交互题)

题面

这是一个互动的问题。

Kachina挑战你猜她最喜欢的长度为 n 的二进制字符串 s 。她将 f(l,r) 定义为 slsl+1sr01 的子序列 的个数。**如果两个子序列是通过删除原字符串中不同位置的字符而形成的,则认为它们是不同的,即使结果子序列由相同的字符组成

要确定 s ,你可以问她一些问题。在每个问题中,您可以选择两个索引 lr ( 1l<rn ),并询问她 f(l,r) 的值。

在向克钦纳询问不超过 n 的问题后,确定并输出 s 。然而, s 可能是无法确定的。在这种情况下,您需要报告 IMPOSSIBLE

形式上, s 是不可能确定的,如果在问了 n 个问题之后,无论问什么问题, s 总是有多个可能的字符串。请注意,如果您报告IMPOSSIBLE**,当存在最多 n 查询序列将唯一地确定二进制字符串时,您将得到错误的答案判决

二进制字符串只包含字符 01

序列 a 是序列 b 的子序列,如果 a 可以从 b 中删除几个(可能为零或全部)元素。例如, 1011101 的子序列是 01 , 11111 , 0111 ,但不是 00011100

题解

这是一道 交互题

首先!我们确定一下, IMPOSSIBLE 的情况暂时确定为 f(1,n)=0 的情况,因为可能全是 1 或者全是 0 (其实也就这种情况)

其次!如果 f(1,i1)<f(1,i) ,那么第 i 位一定是 1 ,因为能和前面的 0 组成 01

同时!如果 f(1,i1)=f(1,i) ,那么第 i 位一定是 0 ,因为不能和前面的数字组成 01

然后!我们设 last 为最前面的且 f(1,last)>01 的位置,那么 f(1,last)<last ,同时,last 前面应该按从前往后顺序为 last1f(1,last)1f(1,last)0

(另外!) 如何找到 last ? 只要判定 f(1,last)<last 即可。

最后!我们可以发现按照上面的方法,从后往前遍历确认的话(记得用数组存起来哦),我们无法确定最前面两位的数字是什么。刚好我们还有最后一次询问机会,那我们直接得到 f(2,n)

  • 如果 f(2,n)=f(1,n) 说明最前面的位一定是 1 ,至于第二位是什么,就比较 2f(1,last) 的关系,如果 last2f(1,last) 那么这一位上就是 0 ,否则就是 1
  • 如果 f(2,n)f(1,n) 说明最前面一位一定是 0 ,至于第二位是什么,就直接看 f(1,2) ,如果 f(1,2)>0 那么第二位就是 1 ,否则就是 0

但是但是!如果这个串只有两位的话,那么最后一步就会报错(OJ,操作不合法,? 2 2 是不合法的),我们只需要在最前面特判一下 n=2 时的情况即可(只有序列为 01 可以确认,其他直接输出 IMPOSSIBLE

代码

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define lowbit(x) x&-x
const int INF = 1e18;
using i64 = long long;
using pii = std::pair<int,int>;
void solve() {
int n;
std::cin >> n;
std::string s;
int rans = INF;
int ans;
int last = INF;
if(n == 2) {
std::cout << "? " << 1 << " " << n << std::endl;
std::cin >> rans;
if(rans == 0) {
std::cout << "! IMPOSSIBLE" << std::endl;
} else {
std::cout << "! 01" << std::endl;
}
return;
}
std::vector<int> mem(n+1);
std::cout << "? " << 1 << " " << n << std::endl;
std::cin >> rans;
ans = rans;
int sum = rans;
if(sum == 0) {
std::cout << "! IMPOSSIBLE" << std::endl;
return;
}
mem[n] = rans;
for(int i = n-1 ; i > 1 ; i--) {
std::cout << "? " << 1 << " " << i << std::endl;
std::cin >> ans;
if(ans == 0 && rans != 0) {
last = i+1;
}
if(ans == rans){
if(ans == 0) {
if(last - (i+1) <= mem[last]){
s.push_back('0');
} else {
s.push_back('1');
}
} else {
s.push_back('0');
}
} else {
s.push_back('1');
}
mem[i] = ans;
rans = ans;
}
if(last == INF) {
last = 2;
}
std::cout << "? " << 2 << " " << n << std::endl;
std::cin >> ans;
if(ans == sum) {
if(last - 2 <= mem[last]) {
s.push_back('0');
} else {
s.push_back('1');
}
s.push_back('1');
} else {
if(mem[2]) {
s.push_back('1');
} else {
s.push_back('0');
}
s.push_back('0');
}
std::reverse(all(s));
std::cout << "! " << s << "\n";
}
signed main() {
int t = 1;
std::cin >> t;
while(t--) {
solve();
}
return 0;
}

posted on   Jiejiejiang  阅读(92)  评论(0编辑  收藏  举报

编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」

导航

统计信息

点击右上角即可分享
微信分享提示