A Twice
题面
Kinich 醒来迎接新的一天的开始。他打开手机,查看邮箱,发现了一份神秘的礼物。他决定打开礼物的盒子。
Kinich 用 \(n\) 整数打开数组 \(a\) 。最初,Kinich的分数是 \(0\) 。他将执行任意次数的以下操作:
—选择两个索引 \(i\) 和 \(j\) \((1 \leq i \lt; j \leq n)\) ,确保在之前的操作中没有选择 \(i\) 和 \(j\) 和 \(a_i = a_j\) 。然后,将 \(1\) 加到他的分数上。
输出 Kinich 在执行上述操作任意次数后可以获得的最大分数。
题解
实际上我们不用管这个数组,我们只要把对出现次数大于 \(2\) 的数字进行记录处理就可以了
对每种出现次数大于 \(2\) 的数字,我们能操作 \(\lfloor 出现次数/2 \rfloor\) 次
最后对其求和即可
具体实现可以用 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 \times m\) 的网格。具体来说,你的输入流应该包含以下内容:
-
第一行包含两个整数 \(n\) 和 \(m\) —— 网格的尺寸。
-
下面的 \(n\) 行包含 \(m\) 个整数 —— 网格的值。
然而,有人截获了你的输入流,打乱了所有给定的整数,并把它们都放在一行上!现在, \(k\) 整数都在一行中,并且您不知道每个整数最初属于哪里。您决定自己确定 \(n\) 和 \(m\) 的值,而不是要求Citlali重新发送输入。
输出Citlali可能提供的 \(n\) 和 \(m\) 的任何可能值。
题解
第一个数是 \(k\) 代表下列一行的长度
下面一行是数,包括矩阵的数字 以及 矩阵的长和宽
因此,矩阵的大小已经确定,即 \(n \times m = k - 2\)
也就是说,我们只要在下面一行中找到能够构成 相乘的乘积等于 \(k-2\) 的一对数即可(不管顺序)
- 最容易想到的暴力算法,时间复杂度为 \(O(n^2)\) ,超时
- 我们可以在 \(O(n)\) 的时间复杂度内实现
从前往后遍历,如果前面出现过能与当前数相乘得到 \(k-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;
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\) 的排列 \(^{\text{∗}}\) \(p\) ,使得 \(p_i + p_{i+1}\) 是所有 \(1 \leq i \leq n - 1\) 的组合 \(^{\text{†}}\) 。如果不可能,输出 \(-1\) 。
\(^{\text{∗}}\) 长度为 \(n\) 的排列是一个由 \(1\) 到 \(n\) 之间任意顺序的 \(n\) 不同整数组成的数组。例如, \([2,3,1,5,4]\) 是一个排列,但 \([1,2,2]\) 不是一个排列( \(2\) 在数组中出现了两次), \([1,3,4]\) 也不是一个排列( \(n=3\) 但数组中有 \(4\) )。
\(^{\text{†}}\) 如果一个整数 \(x\) 除了 \(1\) 和 \(x\) 之外至少有一个除数,那么这个整数 \(x\) 就是合数。例如, \(4\) 是合数,因为 \(2\) 是一个除数。
题解
已知:非 \(2\) 且 非 \(0\) 的 偶数一定是合数
已知:奇数和奇数相加是偶数(大于 \(2\) ),偶数和偶数相加是偶数(大于 \(2\) ),奇数和偶数相加是奇数
已知:最小的奇数合数是 \(9\) ,可以由 \(4\) 和 \(5\) 相加得到
因此:
-
当 \(n \lt 5\) 时,不可能构造成功,直接输出 \(-1\);
-
当 \(n \ge 5\) 时,把 \(5\) 和 \(4\) 放中间。其余奇数和偶数分别放两边,即构造成功
代码
#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\) 位于 \(x_i\) 位置,值为 \(v_i\) 。当 Mualani 在位置 \(x_i\) 时,她可以选择收集能量以增加她的跳跃能力 \(v_i\) 。在同一个位置可能会有多个升级道具。当玩家处于拥有一些能量道具的位置时,他可能会选择接受或忽略每个能量道具。在任何障碍的间隔中都没有能量。
到达位置 \(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\) 的二进制字符串 \(^{\text{∗}}\) \(s\) 。她将 \(f(l, r)\) 定义为 \(s_l s_{l+1} \ldots s_r\) 中 \(\texttt{01}\) 的子序列 \(^{\text{†}}\) 的个数。**如果两个子序列是通过删除原字符串中不同位置的字符而形成的,则认为它们是不同的,即使结果子序列由相同的字符组成
要确定 \(s\) ,你可以问她一些问题。在每个问题中,您可以选择两个索引 \(l\) 和 \(r\) ( \(1 \leq l \lt r \leq n\) ),并询问她 \(f(l, r)\) 的值。
在向克钦纳询问不超过 \(n\) 的问题后,确定并输出 \(s\) 。然而, \(s\) 可能是无法确定的。在这种情况下,您需要报告 \(\texttt{IMPOSSIBLE}\) 。
形式上, \(s\) 是不可能确定的,如果在问了 \(n\) 个问题之后,无论问什么问题, \(s\) 总是有多个可能的字符串。请注意,如果您报告\(\texttt{IMPOSSIBLE}\)**,当存在最多 \(n\) 查询序列将唯一地确定二进制字符串时,您将得到错误的答案判决
\(^{\text{∗}}\) 二进制字符串只包含字符 \(\texttt{0}\) 和 \(\texttt{1}\) 。
\(^{\text{†}}\) 序列 \(a\) 是序列 \(b\) 的子序列,如果 \(a\) 可以从 \(b\) 中删除几个(可能为零或全部)元素。例如, \(\mathtt{1011101}\) 的子序列是 \(\mathtt{0}\) , \(\mathtt{1}\) , \(\mathtt{11111}\) , \(\mathtt{0111}\) ,但不是 \(\mathtt{000}\) 和 \(\mathtt{11100}\) 。
题解
这是一道 交互题 !
首先!我们确定一下, \(\texttt{IMPOSSIBLE}\) 的情况暂时确定为 \(f(1,n) = 0\) 的情况,因为可能全是 \(1\) 或者全是 \(0\) (其实也就这种情况)
其次!如果 \(f(1,i-1) \lt f(1,i)\) ,那么第 \(i\) 位一定是 \(1\) ,因为能和前面的 \(0\) 组成 \(01\)
同时!如果 \(f(1,i-1) = f(1,i)\) ,那么第 \(i\) 位一定是 \(0\) ,因为不能和前面的数字组成 \(01\)
然后!我们设 \(\texttt{last}\) 为最前面的且 \(f(1,\texttt{last}) \gt 0\) 的 \(1\) 的位置,那么 $f(1,\texttt{last}) \lt \texttt{last} $ ,同时,\(\texttt{last}\) 前面应该按从前往后顺序为 \(\texttt{last} - 1 - f(1,\texttt{last})\) 个 \(1\) 和 \(f(1,\texttt{last})\) 个 \(0\)
(另外!) 如何找到 \(\texttt{last}\) ? 只要判定 $f(1,\texttt{last}) \lt \texttt{last} $ 即可。
最后!我们可以发现按照上面的方法,从后往前遍历确认的话(记得用数组存起来哦),我们无法确定最前面两位的数字是什么。刚好我们还有最后一次询问机会,那我们直接得到 \(f(2,n)\)
- 如果 \(f(2,n) = f(1,n)\) 说明最前面的位一定是 \(1\) ,至于第二位是什么,就比较 \(2\) 和 \(f(1,last)\) 的关系,如果 \(\texttt{last} - 2 \le f(1,last)\) 那么这一位上就是 \(0\) ,否则就是 \(1\)
- 如果 \(f(2,n) \neq f(1,n)\) 说明最前面一位一定是 \(0\) ,至于第二位是什么,就直接看 \(f(1,2)\) ,如果 \(f(1,2) \gt 0\) 那么第二位就是 \(1\) ,否则就是 \(0\)
但是但是!如果这个串只有两位的话,那么最后一步就会报错(OJ,操作不合法,? 2 2
是不合法的),我们只需要在最前面特判一下 \(n = 2\) 时的情况即可(只有序列为 \(01\) 可以确认,其他直接输出 \(\texttt{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;
}
标签:std,988,last,contest,int,题解,texttt,long,define
From: https://www.cnblogs.com/jiejiejiang2004/p/18552138