题目链接:
https://www.luogu.com.cn/problem/P1918https://www.luogu.com.cn/problem/P1918
题目:
DL 算缘分算得很烦闷,所以常常到体育馆去打保龄球解闷。因为他保龄球已经打了几十年了,所以技术上不成问题,于是他就想玩点新花招。
DL 的视力真的很不错,竟然能够数清楚在他前方十米左右每个位置的瓶子的数量。他突然发现这是一个炫耀自己好视力的借口——他看清远方瓶子的个数后从某个位置发球,这样就能打倒一定数量的瓶子。
1. ◯ ◯ ◯
2. ◯ ◯ ◯ ◯
3. ◯
4. ◯ ◯
如上图,每个 “◯” 代表一个瓶子。如果 DL 想要打倒 3 个瓶子就在 1 位置发球,想要打倒 4 个瓶子就在 2 位置发球。
现在他想要打倒 m 个瓶子。他告诉你每个位置的瓶子数,请你给他一个发球位置。
输入格式:
第一行包含一个正整数 n,表示位置数。
第二行包含 n 个正整数 ,表示第 i 个位置的瓶子数,保证各个位置的瓶子数不同。
第三行包含一个正整数 Q,表示 DL 发球的次数。
第四行至文件末尾,每行包含一个正整数 m,表示 DL 需要打倒 m 个瓶子
输出格式:
共 Q 行。每行包含一个整数,第 i 行的整数表示 DL 第 i 次的发球位置。若无解,则输出 0。
例:
输入:
5 1 2 4 3 5 2 4 7
输出:
3 0
数据范围:
对于 100% 的数据,1 ≤ n , Q ≤ 100000 , 1 ≤ , m ≤
。
思路:
首先观察题目,题目目标是为了恰好打倒m个瓶子,需要在哪一行发球。
那么需要将行号与该行瓶子数量相绑定。那我们可以定义一种结构体node,其中含有当前行数fir与当前行的瓶子数量num,用于存储哪一行有多少个瓶子。
接着我们按照题意,首先使用整形变量n来接收有多少行,接着循环n次将行数与瓶子数量存入结构体数组arr(我的ac代码中使用vector,因为n只有最小值并且最大值不确定)。
在此处思考一个问题,若我们使用循环来遍历结构体数组来寻找目标值,那么该动作的时间复杂度为O(n),当数据量极大时,我们寻找一次的时间就可能超过限定时间了。所以我们选择时间复杂度较低的搜索算法——二分算法(时间复杂度为O(Log n))来搜索目标行数。
然后对结构体数组进行按瓶子数量排序(因为二分查找需要在一个有序数组中进行)。接着每次接收玩目标瓶子数后,对排序后的数组进行二分查找。
在二分查找后,判断arr[l].num是否与目标瓶数相等。若相等,则输出arr[l].fir;反之,输出0。
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define ll long long
struct node {
ll fir, num;
};
ll n, num, tar;
vector<node> arr;
bool cmp(node x, node y) {
return x.num < y.num;
}
int main() {
scanf("%lld", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld", &num);
arr.push_back({ i,num });
}
sort(arr.begin(), arr.end(), cmp);
scanf("%lld", &n);
while (n--) {
scanf("%lld", &tar);
ll l = 0, r = arr.size();
while ((l + 1) < r) {
ll mid = (l + r) >> 1;
if (arr[mid].num > tar) {
r = mid;
}
else {
l = mid;
}
}
if (arr[l].num == tar) {
printf("%lld\n", arr[l].fir);
}
else {
printf("0\n");
}
}
return 0;
}
如果我的文章对你有所帮助,不妨给我个关注何点赞吧。