题目描述
Saya likes math, because she think math can make her cleverer.
One day, Kudo invited a very simple game:
Given N integers, then the players choose no more than four integers from them (can be repeated) and add them together. Finally, the one whose sum is the largest wins the game. It seems very simple, but there is one more condition: the sum shouldn’t larger than a number M.
Saya is very interest in this game. She says that since the number of integers is finite, we can enumerate all the selecting and find the largest sum. Saya calls the largest sum Greatest Number (GN). After reflecting for a while, Saya declares that she found the GN and shows her answer.
Kudo wants to know whether Saya’s answer is the best, so she comes to you for help.
Can you help her to compute the GN?
输入
The input consists of several test cases.
The first line of input in each test case contains two integers N (0<N≤1000) and M(0 1000000000), which represent the number of integers and the upper bound.
Each of the next N lines contains the integers. (Not larger than 1000000000)
The last case is followed by a line containing two zeros.
输出
For each case, print the case number (1, 2 …) and the GN.
Your output format should imitate the sample output. Print a blank line after each test case.
示例输入
示例输出
提示
这个题我主要是因为前几天刚刚做过一道类似的,那道题目是任意4的数的和拼成一个固定的数。于是就发现了这种题可以用一种先分组,然后再去拼和的方法。做到这个题的时候,马上就想起那个题来了。于是就有了基本思考的方向。但问题是那道题很小,想要做出这道题还需要很多问题需要解决。但是最终方法也只是多用了几次二分而已。。
具体方法是:定义一个数组,分别存着0,1个数,以及各个2个数之间的和,假设分别是a, b, c吧,任意两个数的和可以用原始数组自加得到,为了之后的2分,数组求完后进行排序。然后再用这个数组进行自己与自己相加。a与a相加得到0个数的和;a与b的和得到1个数的和;a与c的和得到2个数的和;b与c的和得到3个数的和;c与c的和得到4个数的和。于是从0到4的各种数字组成的和都找到了。最后就只是挑最接近m但是又不超过m的数了。这里数组是比较大的,所以应该用二分查找,二分查找方法是遍历,每个数与该数组相加的时候用二分然后相加,找到小于m的最大值,然后遍历过去就可以找到最终的最大值了。
本来以为有可能超时,还好该题后台测试数据并不多,还是过了。
Ps:刚刚上网找了找别人的代码。。发现基本都是这么过的(本来还为自己想出这么奇葩的想法而暗暗高兴。。sad。。)不知道还有没有更好的方法。。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int a[2000001];
int cmp(int x, int y)
{
return x < y;
}
int main()
{
int n, m, i, j, mid, l, h, k, max1, x, num=0, g, r, z;
while(scanf("%d%d",&n,&m)!=EOF&&n)
{
k=0;
num++;
a[0]=0;
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
{
if(a[i]>m)
{
i--;
n--;
}
}
}
k=n+1;
for(i=1; i<=n; i++)
{
for(j=i; j<=n; j++)
{
if(a[i]+a[j]<=m)
{
a[k++]=a[i]+a[j];
}
}
}
sort(a,a+k,cmp);
r=k-1;
g=k-1;
max1=0;
for(i=0; i<k; i++)
{
z=0;
l=i;
while(l<=r)
{
mid=(l+r)/2;
x=a[i]+a[mid];
if(x>m)
r=mid-1;
else if(x==m)
{
max1=m;
z=1;
break;
}
else
{
l=mid+1;
if(max1<x)
{
g=mid;
max1=x;
}
}
}
if(z)
break;
r=g;
}
printf("Case %d: %d\n\n",num, max1);
}
return 0;
}