Sumsets
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 11294 | Accepted: 3101 |
Description
![](https://i-blog.csdnimg.cn/blog_migrate/d903c9a08afdf3b6dfac35b18da4660b.jpeg)
Input
Several S, each consisting of a line containing an integer 1 <= n <= 1000 indicating the number of elements in S, followed by the elements of S, one per line. Each element of S is a distinct integer between -536870912 and +536870911 inclusive. The last line of input contains 0.
Output
For each S, a single line containing d, or a single line containing "no solution".
Sample Input
5 2 3 5 7 12 5 2 16 64 256 1024 0
Sample Output
12 no solution
Source
给定一个含有 N 个元素的集合,从集合中选取 a,b,c,d 四个元素,使 a+b+c=d 成立。求最大的d。
显然是一个折半枚举的题。N <= 1000 , 直接枚举 O(n4) 复杂度太高。采用折半枚举的思想,两个两个的枚举。
先枚举两个数的和,再枚举两个数的差。然后用二分搜索把两个值匹配起来,注意元素不能重复利用就好了。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
struct P
{
LL s, x, y;
P(){};
P(LL a, LL b, LL c):
s(a), x(b), y(c){};
bool operator < (P k)
{
return s < k.s;
}
};
const LL inf = 6000000000;
const int maxn = 1000 + 10;
LL S[maxn];
P sum[maxn * maxn];
int N;
bool cmp(LL x, LL y)
{
return x > y;
}
int main ()
{
while(1)
{
cin >> N;
if(N == 0) break;
for(int i= 0; i< N; i++)
scanf("%lld", S+i);
sort(S, S+N, cmp);//将 S 从大到小排序
//枚举连个数的和
int cnt = 0;
for(int i= 0; i< N; i++)
for(int j= i+1; j< N; j++)
{
sum[cnt].x = S[i]; //加数
sum[cnt].y = S[j]; //加数
sum[cnt].s = S[i] + S[j];//和
cnt ++;
}
sort(sum, sum+cnt);//将 sum 从小到大排序
//枚举两个数的差
LL ans = -inf;
for(int i= 0; i< N; i++)
for(int j= 0; j< N; j++)
{
if(i == j) continue;
//二分搜索匹配
P temp (S[i]-S[j], -inf, -inf);
int pos = lower_bound(sum, sum+cnt, temp) - sum;
for(int k= pos; k<cnt && sum[k].s == S[i]-S[j]; k++)
{
//去重
if(sum[k].x != S[i] && sum[k].x != S[j]
&& sum[k].y != S[i] && sum[k].y != S[j])
{
ans = max(ans, S[i]);
}
}
}
if(ans == -inf) cout << "no solution\n";
else cout << ans << endl;
}
return 0;
}