【Poj】2594 Sumsets 折半枚举
题意
给出 n 个数字,求满足\(a+b+c=d\)的 d 的最大值,注意(a,b,c,d) 互不相等。
思路
折半枚举。
首先我们把任意两个数的和求出,排序。
然后从大到小枚举 d 的值,再枚举 c 的值,对于\(d-c\),我们二分找到其在两个数的和中出现的次数。
接下来开始将重复的情况删去。
有三种情况
- \(a+b=a-b\)
- \(a+b=a-c\)
- \(a+b=c-b\)
第一种情况可以知道 b=0
第二种情况可以知道 b=-c
第三种情况可以知道 a=c-2*b
那么我们只需要将这三种重复的情况去掉,如果这时次数还大于0,那么就找到了最大的 d。
退出循环即可。
代码
/*
* @Autor: valk
* @Date: 2020-08-11 12:38:37
* @LastEditTime: 2020-09-28 17:19:07
* @Description: 如果邪恶 是华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <algorithm>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 4e3 + 10;
vector<int>vec,sum;
map<int,int>mp;
int main()
{
int n;
while(~scanf("%d",&n)){
if(!n) break;
vec.clear(),sum.clear(),mp.clear();
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
mp[x]=1;
vec.pb(x);
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
sum.pb(vec[i]+vec[j]);
}
}
sort(vec.begin(),vec.end());
sort(sum.begin(),sum.end());
int ans=-inf;
for(int i=n-1;i>=0;i--){
for(int j=0;j<n;j++){
if(i==j) continue;
int dis=vec[i]-vec[j];
int l=lower_bound(sum.begin(),sum.end(),dis)-sum.begin();
int r=upper_bound(sum.begin(),sum.end(),dis)-sum.begin();
int num=r-l;
if(vec[j]==0) num--;
if(mp[-vec[j]]) num--;
if(mp[dis-vec[j]]) num--;
if(num>0) {
ans=vec[i];
break;
}
}
if(ans!=-inf) break;
}
if(ans!=-inf) printf("%d\n",ans);
else printf("no solution\n");
}
return 0;
}