题目:Min Value
来源:哈尔滨理工大学软件与微电子学院程序设计竞赛(同步赛)
解题思路
给定一个由 个数组成的序列
,从中任选两个数
和
,使得
的绝对值最小,并且计算出
的值,其中
。
使用双指针。
先将序列中的数从小到大排序。如果两个数相等,下标小的排前面。a[i][0] 表示第 i 小的数值,a[i][1] 是其对应的原下标。
将 i 和 j 分别指向排序后序列的首元素和尾元素。
- 如果
a[j-1][0] == a[j][0],数值相等,但a[j-1][1] < a[j][1],将j左移。 i和j指向的数值均大于等于 0,那么不管是i还是j向右移,两数相加的绝对值均比现在要大,所以将j左移。i和j指向的数值均小于等于 0,那么不管是i还是j向左移,两数相加的绝对值均比现在要大,所以将i右移。i指向的值小于 0,j指向的值大于 0,哪边的绝对值大,移动哪边。
比如,i指向x <= 0,j指向y >= 0,则两者相加的绝对值为abs(-x - y),如果-x > y,小于y的值与x相加得到的绝对值一定大于当前的绝对值,将j左移没有必要,所以将i右移;否则将j左移。
C++代码
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
bool comp(vector<int>& v1, vector<int>&v2){
if(v1[0] < v2[0])
return true;
else if(v1[0] == v2[0])
return v1[1] < v2[1];
return false;
}
int main(){
int N;
scanf("%d", &N);
vector<vector<int>> a(N, vector<int>(2));
for(int i=0; i<N; ++i){
scanf("%d", &a[i][0]);
a[i][1] = i+1;
}
sort(a.begin(), a.end(), comp);
long long minVal = 1e12+1;
int minIndex = 2e5;
int i = 0;
int j = N-1;
while(i < j){
long long sum = abs(1LL * a[i][0] + a[j][0]);
if(sum < minVal){
minVal = sum;
minIndex = a[i][1] + a[j][1];
}
else if(sum == minVal){
minIndex = min(minIndex, a[i][1] + a[j][1]);
}
if(a[j][0] == a[j-1][0])
--j;
else if(a[i][0] >= 0)
--j;
else if(a[j][0] <= 0)
++i;
else{
if(-a[i][0] > a[j][0])
++i;
else
--j;
}
}
printf("%lld %d\n", minVal, minIndex);
return 0;
}
京公网安备 11010502036488号