www.codefun2000.com 是一个收集各种笔试题目,供大家学习交流,体会笔试难度的OJ网站。
由于第三题的一些细节一直没有思考通,故拖到现在才发出来。
第一题
题目描述
塔子哥是一个数学爱好者,他经常思考各种数字之间的奥秘。今天,他想要解决一个有趣的问题:如何在一个数字中插入一个数字,以得到最大的结果?他发现这个问题很有挑战性,因为他必须找到一种方法,能够在给定的数字中插入一个数字,使得插入后的结果最大。于是,他开始思考并设计了一种算法来解决这个问题。
算法的核心思想是:首先将第一个数字转化为字符串,然后将第二个数字插入到字符串的不同位置,得到多个可能的结果。最后,从中选择最大的一个数字作为最终的结果。
塔子哥已经写好了这个算法,并请你帮忙测试一下。请编写一个程序,输入塔子哥手上的两个数字,输出插入后得到的最大数字。(前导零正常输出)
输入描述
输入第一行为一个数字,表示有组测试样例。接下来的行对于每一组数据,包含一行有2个空格隔开的整数,表示任意正整数 和待插入的数字 。
其中,
输出描述
对于每组数据,输出一行,包括一个整数,得到最大的整数。
样例
输入
3
9
0 0 1 0 0 1 0 0 1
6
1 1 0 1 1 0
4
1 0 0 0
输出
5 4 4 4 3 5 3 2 6
3 2 3 2 1 4
0 3 2 1
思路
这题是一个很简单的贪心算法,即从最高位开始找,找到第一个比数字小的位,并将插入到该位之前,如果没有找到比大的数位,则将插入到最后 这道题我主要犯了两个错误,导致没能成功ac。
- 没有考虑溢出的情况(经典错误)。但事实上即使用上了long long依旧有部分用例溢出,
- 虽然题中说到,但事实上有如下测试用例,不知道题目最后提到的“(前导零正常输出)”是否与这个问题相关。
1
0 1
另外还有一些小问题:
- C++的cin可以直接将标准输入的内容放入string类型中,而不一定是整型类型。没必要先以整型接收,再使用to_string()进行转换。
// 将输入放入字符串中
string a;
cin >> a;
// 将输入放入长整型中
long long a;
cin >> a;
- 平时习惯了Leetcode的核心代码模式,因此总是习惯于将答案存储在一个变量中再做输出,而这在ACM模式中其实完全没有必要。以本题为例,我用了一个链表来存储a的每一个数字,并将b实际地插入了a,再将链表转为整型输出。而实际上,并不需要实际地将b插入a中,只需要先输出a的前一部分,再输出b,最后输入a的后一部分即可。
code
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int T;
cin >> T;
for(int i = 0; i < T; ++i) {
string a;
int b;
cin >> a >> b;
int idx = -1;
for(int i = 0; i < a.size(); i++){
int t = a[i] - '0';
if(b > t){
idx = i;
break;
}
}
// 没找到比b小的数字,将b插入a的最后
if(idx == -1) idx = a.size();
// 先输出a的前一部分,输出b,最后输入a的后一部分
cout << a.substr(0, idx) << b << a.substr(idx) << endl;
}
return 0;
}
对于每个测试样例,事件复杂度为
第二题
简单的前缀和加后缀和,略
第三题
题目描述
塔子哥是一位火车车厢调度员。
这一天,一列带有 n 个编号车厢的列车进站了,编号为 1~n 。但是,这些车厢的编号并不是按从左到右递增的顺序,为了后面的工作方便展开,塔子哥想把火车调整成从左到右递增的顺序,即 [1,2,3,……n] ,但他只能进行一种操作:首先他要在火车中任意选择两个车厢取出。然后他将两个车厢中较大的放在火车的最右边,较小的放在火车的最左边。
他可以进行无限次这样的操作,他想知道最少需要多少次才能将火车调整为从左到右递增的顺序。
输入描述
第一行是数组的长度: . 第二行有n个数字 表示从左到右的车厢编号。
其中,
输出描述
输出一个整数,表示最少需要操作多少次。
样例
样例输入
7
1 3 5 2 4 6 7
样例输出
3
思路
我开始时理解错了题意,以为是选中两个元素然后进行位置交换,但实际上是选择两个元素,将其中大的放在火车的最右端,小的放在火车的最左端。
这道题与Codeforce的1792C Min Max Sort一致,我翻译了Tutorial里的题解,补充了部分自己的理解,并修改了原代码的贴于下文。
考虑最简单的情况,如果火车编号本来就是升序的,那么不需要操作,答案为。如果不是升序的,最后一次操作一定是选择选择火车中最大和最小编号的两个车厢,即和,否则操作结束后不可能第一个编号是,最后一个编号是。
接下来考虑区间,如果区间里的编号是升序的,那么答案就是1,否则,完全类似的,最后第二个操作应该是选择和;如果区间的编号是升序的,那么答案就是2,否则,完全类似的,最后第三个操作应该是选择和;依此类推,直到剩下的区间是升序的或者为空为止。
注意这里的元素值是每个编号在原排列中的位置,而不是原排列中的每个位置对应的编号值(但这点我始终没有思考明白,为什么使用后者是不正确的,我还得再思考思考,也希望大家能帮我解答一下)。
如此,本题就转换为如何找到最大的使得区间是升序的。
这就很简单了,从最大的开始,向两边扩展,直到左侧元素比右侧的大,或者右侧元素比左侧小为止。另外一个方法是使用二分搜索。
code
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> pos(n + 1);
for (int i = 0; i < n; ++i) {
int x;
cin >> x;
pos[x] = i;
}
int l = (n + 1) / 2, r = (n + 2) / 2;
while (l > 0 && (l == r || (pos[l] < pos[l + 1] && pos[r - 1] < pos[r]))) {
--l;
++r;
}
cout << (n - r + l + 1) / 2 << '\n';
}
第四题
模拟,但当时我时是没看懂题意的,我太菜了。