[关闭]
@Asuna 2017-02-02T02:47:59.000000Z 字数 4331 阅读 745

2016寒假集训队第一次作业

题解


Problem A:Strange fuction

题意:给定一个f(x)=6*x^7+8*x^6+7*x^3+5*x^2-y*x,求出它在x属于[0,100]的时候的最小值。

题解:综合题目大意和本次作业的主题。。很容易想到要用三分法求最值(二分法要求单调),于是。。这道题似乎就是一个裸的三分了。。。。(注意要保留4位小数而题目中没说哦~)

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. using namespace std;
  5. int t;
  6. double y,mid,mmid,l,r;
  7. double getf(double x,double y)
  8. {
  9. return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*pow(x,2)-y*x;
  10. }
  11. int main()
  12. {
  13. cin>>t;
  14. while(t--)
  15. {
  16. cin>>y;
  17. l=0;
  18. r=100;
  19. for (int i=0; i<200; i++)
  20. {
  21. mid=(l+r)/2;
  22. mmid=(mid+r)/2;
  23. if (getf(mid,y)<getf(mmid,y)) r=mmid;
  24. else l=mid;
  25. }
  26. printf("%.4lf\n",getf(mid,y));
  27. }
  28. return 0;
  29. }

Problem B:Can you find it?

题意:给定三个数列,长度分别为l,m,n,都属于0~500。现在要任意组合这三个数列中的数看相加能否为x,能输出yes,不能输出no,有1000个询问。

题解:一开始想的是直接三个数列依次相加,但是这样是500*500*500*1000,不用想肯定会爆炸。再加上这次的主题是二分,于是想到了一个算法:把一个数列拿去排序然后二分看能否等于x,但在t了几发之后发现好像500*500*log500*1000也会爆炸。。。然后想了一会儿发现自己傻逼了,既然可以一个拿来二分,那就可以预处理出三个数组中两个数组的和的值,放在一个新的数组里面然后就可以优化成500*log(500*500)*1000,这样就不会爆炸了(智商受限严重)。。。

参考代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. using namespace std;
  4. int l,m,n,d=1,t,k;
  5. long long x;
  6. bool bo1,bo2;
  7. int main()
  8. {
  9. ios::sync_with_stdio(false);
  10. while(cin>>l>>m>>n)
  11. {
  12. long long a[505],b[505],c[505],p[250005];
  13. k=1;
  14. for(int i=1; i<=l; i++)
  15. cin>>a[i];
  16. for(int i=1; i<=m; i++)
  17. cin>>b[i];
  18. for(int i=1; i<=n; i++)
  19. cin>>c[i];
  20. for(int i=1; i<=l; i++)
  21. for(int j=1; j<=m; j++)
  22. {
  23. p[k]=a[i]+b[j];
  24. //cout<<p[k]<<" ";
  25. k++;
  26. //cout<<p[k]<<" ";
  27. }
  28. //cout<<endl;
  29. sort(p+1,p+k);
  30. //for (int i=1; i<=k-1; i++)
  31. // cout<<p[k]<<" ";
  32. cin>>t;
  33. cout<<"Case "<<d++<<":"<<endl;
  34. while(t--)
  35. {
  36. cin>>x;
  37. bo1=false;
  38. bo2=false;
  39. for (int i=1; i<=n; i++)
  40. {
  41. int l=1,r=k-1;
  42. while (l<=r)
  43. {
  44. int mid=(l+r)/2;
  45. if (p[mid]+c[i]==x)
  46. {
  47. bo1=true;
  48. bo2=true;
  49. break;
  50. }
  51. else if (p[mid]+c[i]<x)
  52. {
  53. l=mid+1;
  54. }
  55. else r=mid-1;
  56. }
  57. if (bo1) break;
  58. }
  59. if (bo1) cout<<"YES"<<endl;
  60. else cout<<"NO"<<endl;
  61. }
  62. }
  63. return 0;
  64. }

Problem C: Monthly Expense

题意:已知农夫在n天中每天的花费,要求把这n天分作m组,每组的天数必然是连续的,要求分得各组的花费之和应该尽可能地小,最后输出各组花费之和中的最大值。

题解:二分答案,可知最小的可能就是a[i]中的最大值,而最大的可能是整个a数组的和,于是取到了l和r,二分答案检查是否满足刚好可以分为m组,如果大于m组说明偏小了,可以增大,反之可以减小。

参考代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. using namespace std;
  5. int n,m,sum,t,a[100005],ans,l,r,mid;
  6. bool judge(int ans)
  7. {
  8. sum=0;
  9. t=1;
  10. for (int i=1; i<=n; i++)
  11. {
  12. if (sum+a[i]<=ans) sum+=a[i];
  13. else
  14. {
  15. sum=a[i];
  16. t++;
  17. }
  18. }
  19. if (t>m) return 0;
  20. else return 1;
  21. }
  22. int main()
  23. {
  24. cin>>n>>m;
  25. for (int i=1; i<=n; i++)
  26. {
  27. cin>>a[i];
  28. l=max(l,a[i]);
  29. r+=a[i];
  30. }
  31. while (l<=r)
  32. {
  33. mid=(l+r)/2;
  34. if (judge(mid)) r=mid-1;
  35. else l=mid+1;
  36. }
  37. cout<<mid<<endl;
  38. return 0;
  39. }

Problem D:River Hopscotch

题意:有一条河长L,中间N块石头,最多去掉M块,求任意两个石头间最小距离的最大值.

题解:二分最小值,再比较最小值是mid时去掉的石头个数来改动l和r,题目的思路和C类似。值得注意的是有可能把所有石子全部取完。。所以在二分的初始时候要把r设置的大一些(wa了两发。。。)

参考代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cmath>
  4. #include<cstring>
  5. using namespace std;
  6. int l,n,m,a[50005],t,k,l1,r,mid;
  7. bool judge(int mid)
  8. {
  9. t=0;
  10. k=0;
  11. int i=1;
  12. while (i<=n+1)
  13. {
  14. if (a[i]-a[k]>=mid)
  15. {
  16. i++;
  17. k=i-1;
  18. }
  19. else
  20. {
  21. i++;
  22. t++;
  23. }
  24. }
  25. if (t<=m) return 1;
  26. else return 0;
  27. }
  28. int main()
  29. {
  30. cin>>l>>n>>m;
  31. a[0]=0;
  32. a[n+1]=l;
  33. for (int i=1; i<=n; i++)
  34. cin>>a[i];
  35. sort(a,a+n+1);
  36. l1=0;
  37. r=l+l;
  38. while (r-l1>1)
  39. {
  40. mid=(r+l1)/2;
  41. if (judge(mid)) l1=mid;
  42. else r=mid;
  43. }
  44. cout<<l1<<endl;
  45. return 0;
  46. }

Problem E:Communication System

题意:有n种设备,而每种设备分别可以有m1、m2、m3、...、mn个厂家提供生产,而每个厂家生产的同种设备都会存在两个方面的差别:B和P。每种设备都各需要1个,考虑到性价比问题,要求所挑选出来的n件设备,要使得B/P最大。其中B为这n件设备的带宽的最小值,P为这n件设备的总价。

题解:额。。看了下数据范围。。发现好像只要枚举所有可能符合条件的B值也可以。。。就没有用二分来做。。。

参考代码:

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. using namespace std;
  5. struct note
  6. {
  7. int b,p;
  8. }a[105][105];
  9. int n,num[105],maxx[105],minn[105],t,sum,s1,s2,mp;
  10. double ans;
  11. int find(int b)
  12. {
  13. sum=0;
  14. for(int i=1; i<=n; i++)
  15. {
  16. mp=1000000000;
  17. for(int j=1; j<=num[i]; j++)
  18. {
  19. if (a[i][j].b>=b)
  20. mp=min(mp,a[i][j].p);
  21. }
  22. sum+=mp;
  23. }
  24. return sum;
  25. }
  26. int main()
  27. {
  28. cin>>t;
  29. while(t--)
  30. {
  31. ans=0;
  32. cin>>n;
  33. for (int i=1; i<=n; i++)
  34. {
  35. cin>>num[i];
  36. for(int j=1; j<=num[i]; j++)
  37. cin>>a[i][j].b>>a[i][j].p;
  38. }
  39. for(int i=1; i<=n; i++)
  40. {
  41. minn[i]=a[i][1].b;
  42. maxx[i]=a[i][1].b;
  43. for (int j=2; j<=num[i]; j++)
  44. {
  45. maxx[i]=max(maxx[i],a[i][j].b);
  46. minn[i]=min(minn[i],a[i][j].b);
  47. }
  48. }
  49. s1=minn[1];
  50. s2=maxx[1];
  51. for(int i=2; i<=n; i++)
  52. {
  53. s1=min(s1,minn[i]);
  54. s2=min(s2,maxx[i]);
  55. }
  56. for(int i=s1; i<=s2; i++)
  57. ans=max(ans,(double)i/(double)find(i));
  58. printf("%.3lf\n",ans);
  59. }
  60. return 0;
  61. }

Problem F:Light Bulb

题意:求人从左向右走动时,影子的长度L的最大值。

题解:感觉是一道数学题。。因为明显从灯下开始往右走影子先会慢慢变长,但是到了某一点影子开始投射在墙上,于是又会慢慢变短。因此这个函数是一个先增后减的函数,满足三分法。。然后推出L和人到灯的水平距离x满足函数式L=D-x+H-D*(H-h)/x。然后x的初始值可以由相似三角形得到h/H=(D-x)/D => x=D-D*h/H,x最大值为D,即确定了l一开始为D-D*h/H,r一开始为D。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. using namespace std;
  5. double D,H,h,l,r,mid,mmid;
  6. int t;
  7. double getf(double x)
  8. {
  9. return D-x+H-D*(H-h)/x;
  10. }
  11. int main()
  12. {
  13. int t;
  14. cin>>t;
  15. while(t--)
  16. {
  17. cin>>H>>h>>D;
  18. l=(H-h)*D/H;
  19. r=D;
  20. while (l<r-0.0000000001)
  21. {
  22. mid=(l+r)/2;
  23. mmid=(mid+r)/2;
  24. if (getf(mid)>=getf(mmid)) r=mmid;
  25. else l=mid;
  26. }
  27. printf("%.3lf\n",getf(mid));
  28. }
  29. return 0;
  30. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注