给定一个长度为 n 的序列 A,A 中的数各不相同。对于 A 中的每一个数 AiAi,求:
min1≤j<i|Ai−Aj|min1≤j<i|Ai−Aj|
以及令上式取到最小值的 j(记为 PiPi)。若最小值点不唯一,则选择使 AjAj 较小的那个。
输入格式
第一行输入整数n,代表序列长度。
第二行输入n个整数A1…AnA1…An,代表序列的具体数值,数值之间用空格隔开。
输出格式
输出共n-1行,每行输出两个整数,数值之间用空格隔开。
分别表示当i取2~n时,对应的min1≤j<i|Ai−Aj|min1≤j<i|Ai−Aj|和PiPi的值。
数据范围
n≤105n≤105,|Ai|≤109|Ai|≤109
输入样例:
3
1 5 3
输出样例:
4 1
2 1
找到题目用直接暴力法求最小值,会超时
#include <iostream>
#include <algorithm>
#include <cmath>
#include <climits>
using namespace std;
const int N = 100010;
int main()
{
int n;
int arr[N];
scanf("%d", &n);
for (int i = 0; i<n; i++) {
scanf("%d", &arr[i]);
}
int res, tempj=0;
for (int i = 1; i < n; i++) {
res = INT_MAX;
for (int j = 0; j < i; j++) {
if (abs(arr[i] - arr[j]) < res || (abs(arr[i] - arr[j])==res && arr[j]<arr[tempj])){
res = abs(arr[i] - arr[j]);
tempj = j;
}
}
printf("%d %d\n", res, tempj + 1);
}
}
因为这里的每一个数都不相同,而且具有顺序性,所以可以动态维护一个set,通过 lower_bound函数找到一个比该元素大和一个比该元素小,取绝对值最小的即可
这里要注意一些细节,为了避免边界,比如在lower_bound(value)的时候没有比value大的数,以及以及value就是最小的数,只有一个数比value大,在iter--的时候会出问题,所以为了避免边界,像容器中塞入两个INT_MAX, INT_MIN哨兵,但是这个时候在运算的时候可能会爆INT,需要用long long来存
同时注意题目中数组的下标是从1开始。
#include <iostream>
#include <climits>
#include <set>
typedef long long LL;
using namespace std;
int main()
{
int n, value;
scanf("%d", &n);
set<pair<int,int>> s; // set默认按value从小到大排序
s.insert({ INT_MAX,0 }); // 最大值哨兵
s.insert({ INT_MIN,0 }); // 最小值哨兵
for(int i=0;i<n;i++){
scanf("%d", &value);
if (i > 0) {
auto it = s.upper_bound({ value,0 }); // 返回大于等于value 最小的那一个数
auto jt = it;
jt--;
LL rightValue = (LL)it->first - (LL)value;
LL leftValue = (LL)value - (LL)jt->first;
if (leftValue <= rightValue)
printf("%lld %d\n", leftValue, jt->second+1);
else
printf("%lld %d\n", rightValue, it->second+1);
}
s.insert({value,i});
}
}