问题一:开花
问题描述
小A所在的学校又迎来了一年一度的开花活动,有 n 名学生被评为文学优秀奖,m 名学生被评为体育优秀奖。现已知两个奖项获奖同学的编号,每个同学都有唯一的编号。只有同时被评为文学优秀奖和体育优秀奖的学生才能开花,小A想知道开花的名单,请你帮他统计一下。
输入格式
第一行两个整数 ,分别表示文学优秀奖和体育优秀奖的获奖人数。
第二行 n 个不同的整数,表示获得文学优秀奖的同学编号。
第二行 m 个不同的整数,表示获得体育优秀奖的同学编号。
所有编号为正整数且不超过 。
输出格式
一行若干个空格分隔的整数,表示开花的同学编号,按文学优秀奖的先后次序输出。
样例输入
4 4 5 1 7 3 2 3 4 1
样例输出
1 3
问题解析
也就是对每个文学优秀奖的获得者,在体育优秀奖中查找即可。也就是在一个数组中找一个数,也就转化为二分搜索问题。
二分搜索代码如下:(应该记住)
int binary_search(int x, int l, int r){
while(l <= r){
int mid = (l + r) >> 1;
if(t[mid] == x){
return mid;
}
if(t[mid] < x){
l = mid + 1;
}else{
r = mid - 1;
}
}
return -1;
}
代码
#include<bits/stdc++.h>
using namespace std;
int t[100005];
int w[100005];
int binary_search(int x, int l, int r){
while(l <= r){
int mid = (l + r) >> 1;
if(t[mid] == x){
return mid;
}
if(t[mid] < x){
l = mid + 1;
}else{
r = mid - 1;
}
}
return -1;
}
int main(){
int n, m;
cin >> n >> m;
for(int i = 0; i < n; ++i){
cin >> w[i];
}
for(int i = 0; i < m; ++i){
cin >> t[i];
}
sort(t, t + m);
int t = 0;
for(int i = 0; i < n; ++i){
if(binary_search(w[i], 0, m - 1) != -1){
t++;
if(t == 1) cout << w[i];
else{
cout << " " << w[i];
}
}
}
return 0;
}
问题二:切割钢管
问题描述
小A是某工地的计算工程师。工地现有 n 根钢管,第 i 根钢管的长度为 。
现在想用这 n 根钢管来做一个支撑用的柱子。我么可以切割这些钢管成为更短的钢管,但是不能缝合两根钢管。为了安全起见,柱子必须用 至少 k 根长度相同的钢管加上混凝土制成,并且要求钢管长度必须为 整数。
小A想知道,这个柱子最高能建成多高(钢管可以有剩余)。
输入格式
输入第一行一个整数 。
接下来一行输入 n 个空格隔开的整数 ,表示每根钢管的长度。
输出格式
输出最大的高度。
样例输入1
2 4 8 4
样例输出1
2
样例输入2
8 8 12 3 14 12 14 20 4 8
样例输出2
7
问题分析
这里我们对答案进行二分,找到一个可行的答案即可!最后输出的是 r - 1,因为我们保证的是 l 是可行的范围, r 是不可行的范围,最后需要减一,使得答案是可行的。
代码
#include<bits/stdc++.h>
using namespace std;
int a[10010];
int main(){
int n, k;
cin >> n >> k;
for(int i = 0; i < n; i++){
cin >> a[i];
}
int l = 0, r = 100000001;
while(l < r){
int mid = (l + r) >> 1;
int cnt = 0;
for(int i = 0; i < n; i++){
cnt += a[i] / mid;
}
if(cnt >= k){
l = mid + 1;
}else{
r = mid;
}
}
cout << r - 1;
return 0;
}
问题三:跳石头
问题描述
一年一度“跳石头”比赛又要开始了!
这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 N 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。
为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 M 块岩石(不能移走起点和终点的岩石)。
输入格式
输入第一行包含三个整数 L,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。
接下来 N 行,每行一个整数,第 i 行的整数 表示第 i 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。
输出格式
输出只包含一个整数,即最短跳跃距离的最大值。
数据范围
对于 20% 的数据,。
对于 50% 的数据,。
对于 100% 的数据,,。
样例说明
将与起点距离为 2 和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。
样例输入
25 5 2 2 11 14 17 21
样例输出
4
问题分析
对于这些类似 “最短最长”、“最小最大” 等题目,我们经常可以使用二分答案来验证即可。
我们先看看对答案怎么判断可行的?
如果一个答案 x 可行,它要满足在跳跃的距离最短为 x 的时候,尽可能少移走石头。于是,我们统计在 x 的情况下,移走石头的数量 cnt 与题目要求的移走石头的数量 m 进行对比即可。now 代表当前所在的石头号,通过比对,如果发现间隔小于 x ,则必须进行一次移走石头,否则不能保证最短跳跃距离为 x。
bool check(int x){
//now是当前站在哪
//cnt是必须移走多少块石头
int cnt = 0, now = 0;
//从当前站的位置,考虑面前的每一块石头
for(int i = 1; i <= n + 1; i++){
//如果石头间的距离比 x 要小,则需要移走,因为如果不移走,这次跳跃的距离就短了。
if(stone[i] - stone[now] < x){
cnt++;
} else{
//距离够的话,考虑跳下一步
now = i;
}
}
//cnt计算的是,在我们固定了跳多远的情况下,移走尽可能少的石头。
return cnt <= m;
}
下一步,我们需要对可能的答案进行二分查找即可。
代码
#include<bits/stdc++.h>
using namespace std;
int stone[50002];
int l, n, m;
bool check(int x){
//now是当前站在哪
//cnt是必须移走多少块石头
int cnt = 0, now = 0;
//从当前站的位置,考虑面前的每一块石头
for(int i = 1; i <= n + 1; i++){
//如果石头间的距离比 x 要小,则需要移走,因为如果不移走,这次跳跃的距离就短了。
if(stone[i] - stone[now] < x){
cnt++;
} else{
//距离够的话,考虑跳下一步
now = i;
}
}
//cnt计算的是,在我们固定了跳多远的情况下,移走尽可能少的石头。
return cnt <= m;
}
int binary_search(int l, int r){
int ans;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)){
ans = mid;
l = mid + 1;
} else{
r = mid - 1;
}
}
return ans;
}
int main(){
cin >> l >> n >> m;
//stone[0] = 0
//从 1 开始,方便我们每一步跳
for(int i = 1; i <= n; i++){
cin >> stone[i];
}
//把最后一个填充
stone[n + 1] = l;
cout << binary_search(1, l);
return 0;
}
问题四:转圈游戏
问题描述
n 个小伙伴(编号从 0 到 n-1)围坐一圈玩游戏。按照顺时针方向给 n 个位置编号,从 0 到 n-1。最初,第 0 号小伙伴在第 0 号位置,第 1 号小伙伴在第 1 号位置,……,依此类推。
游戏规则如下:每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,……,依此类推,第 n−m 号位置上的小伙伴走到第 0 号位置,第 n−m+1 号位置上的小伙伴走到第 1 号位置,……,第 n−1 号位置上的小伙伴顺时针走到第 m−1 号位置。
现在,一共进行了 轮,请问 x 号小伙伴最后走到了第几号位置。
输入格式
输入共 1 行,包含 4 个整数 n、m、k、x,每两个整数之间用一个空格隔开。
输出格式
输出共 1 行,包含 1 个整数,表示 轮后 x 号小伙伴所在的位置编号。
数据范围
对于 30% 的数据,;
对于 80% 的数据,;
对于 100% 的数据,,,,。
样例输入
10 3 4 5
样例输出
5
问题分析
他们围成一个圈,走第一轮, x 会走到 x + m 模 n 号,走第二轮, x 会走到 x + 2 * m 模 n 号,以此类推,第10的k次方,会走到 x + 10^k * m 模 n。难点就在于求10的k次方。
快速幂
LL pow_mod(LL a, LL b){ LL res = 1; while(b > 0){ if(b & 1){ res = res * a % n; } a = a * a % n; b >>= 1; } return res; }
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, k, x;
typedef long long LL;
LL pow_mod(LL a, LL b){
LL res = 1;
while(b > 0){
if(b & 1){
res = res * a % n;
}
a = a * a % n;
b >>= 1;
}
return res;
}
int main(){
cin >> n >> m >> k >> x;
cout << (x + pow_mod(10, k) * m % n) % n;
return 0;
}