链接:https://ac.nowcoder.com/acm/contest/134/A
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
铁子从森林里收集了n根木棍,她开始将它们按顺序的排成一排,从左到右依次为1到n,她回想起
在数学课上老师教她的三角形知识,她开始从这些木棍中间找三根木棍来组成一个周长最大的三角形,
这时她的兄弟顺溜偷偷的溜了过来,偷走了第i根木棍,现在她想知道现在能够组成周长最大的三角形
的周长是多少?
输入描述:
第一行两个整数n和q。(1 ≤ n, q ≤ 10^5)
第二行n个整数表示第i根木棍的长度ai。(1 ≤ ai ≤ 10^9)
接下来q行,每行一个整数表示被顺溜偷走的木棍编号。注意每行的事件是独立的,也就是说每一次操作都是对于原来的n根木棍进行的。
输出描述:
对于每个询问输出一行表示答案,如果删除木棍后无法组成三角形则输出 -1 。
示例1
输入
6 2
1 2 3 4 5 6
6
5
输出
12
13
解题思路:
构成三角形的原则是任意两边之和大于第三边,且题目要求求周长最大的三角形,那么木棍按长度排序后,选取最长的三个木棍判断是否构成三角形。如果不构成三角形,更换第二长的或第三长的也无法构成三角形(因为第二长和第三长的木棍已经是剩下木棍中长度和最大的),所以此时舍弃最长的木棍向后查找直到找到即可,时间复杂度O(n)。
int最大值为2147483647,而木棍长度最大值为10^9,3根木棍的长度和可能大于int最大值,所以最后结果需要用long long存储。
AC代码:
#include <iostream>
#include <algorithm>
using namespace std;
//排序会打乱下标,而题目对于每个询问需要排除指定下标的木棍,所以用结构体记录原下标
struct Elem {
int index, length;
};
bool cmp(Elem a, Elem b){
return a.length > b.length;
}
int main(){
int n, q;
Elem a[100001] = {};
cin >> n >> q;
for(int i = 0; i < n; i++){
//index + 1与题目输入对应
a[i].index = i + 1;
cin >> a[i].length;
}
//对长度进行降序排序
sort(a, a + n, cmp);
while(q--){
int t;
cin >> t;
//默认选取最大的3个(记录下标)
int choose_index[3] = {0, 1, 2};
do{
if(choose_index[2] >= n){
break;
}
//如果不能构成三角形
if(a[choose_index[2]].length + a[choose_index[1]].length <= a[choose_index[0]].length){
//舍弃最大的
choose_index[0]++;
//重复的下标后移
for(int i = 1; i < 3; i++){
if(choose_index[i] == choose_index[i - 1]){
choose_index[i]++;
}
}
}
if(choose_index[2] >= n){
break;
}
//判断是否有被舍弃的木棍
for(int i = 0; i < 3; i++){
if(a[choose_index[i]].index == t){
choose_index[i]++;
}
}
for(int i = 1; i < 3; i++){
if(choose_index[i] == choose_index[i - 1]){
choose_index[i]++;
}
}
//如果较短的两边之和小于第三边,则继续选择
}while(choose_index[2] < n && a[choose_index[2]].length + a[choose_index[1]].length <= a[choose_index[0]].length);
//如果越界说明找完了也没有符合条件的木棍
if(choose_index[2] >= n){
cout << -1 << endl;
} else {
long long sum = 0;
for(int i = 0; i < 3; i++){
sum += a[choose_index[i]].length;
}
cout << sum << endl;
}
}
}