poj2976(二分搜索,最大化平均值)

题目描述:

    给了两个数组a,b,a[i]和b[i]是相对应的,不能改变位置,去掉其中的一些元素,然后计算最大的r=∑a[i]/∑b[i];

  这道题乍一看是对a[i]/b[i]进行排序然后取前n-k个,但其实是不对的

题解:由题意得,我们要求的是r,所以对式子进行变形:设A=∑a[i],B=∑b[i],则A=r×B,A-r×B=0。所以为了求得最大的r,我们就要求使得A-rxB>0的最大的r,这样我们就可以另ci=ai-bi*r,然后对数组c进行排序即可

代码和学到的东西见下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #define ll long long
 6 #define mem(a,b) memset(a,b,sizeof(a))
 7 using namespace std;
 8 ll a[1005],b[1005];
 9 double c[1005];
10 int n,k;
11 bool cmp(ll a,ll b)
12 {
13     return a>b;
14 }
15 void trans(double x)
16 {
17     for(int i=1;i<=n;i++)
18     {
19         c[i]=100*a[i]-x*b[i];此处可以不乘100,在下面输出的时候再×100,可以省去很多计算
20     }
21     sort(c+1,c+1+n,cmp);
22 }
23 void ini()
24 {
25     mem(a,0);
26     mem(b,0);
27     mem(c,0);
28 }
29 int main()
30 {
31     while(scanf("%d%d",&n,&k)&&k+n>0){
32         //ini();
33     for(int i=1;i<=n;i++) scanf("%d",a+i);
34     for(int i=1;i<=n;i++) scanf("%d",b+i);
35     double l=0,r=1000;
36     for(int i=1;i<=50;i++)
37     {
38         double mid=(l+r)/2;
39         trans(mid);
40         double res=0;
41         for(int j=1;j<=n-k;j++)
42         {
43             res+=c[j];
44         }
45         if(res>=0) l=mid;
46         else if (res<0) r=mid;
47         //printf("mid=%lf\n",mid);
48     }
49     printf("%d\n",(int)((l+r)/2+0.5));}//此处是四舍五入处理
50     //此处也可以输出l或者r,因为二分100次后小数位数而让输出整数已经可以忽略l和r的差异
51     return 0;
52 }

二分的题一定要注意精度!!

posted @ 2018-12-26 14:59  codeoos  阅读(361)  评论(0编辑  收藏  举报