第二次组队赛 二分&三分全场

网址:CSUST 7月30日(二分和三分)

这次的比赛是二分&三分专题,说实话以前都没有接触过二分,就在比赛前听渊神略讲了下.......不过做着做着就对二分熟悉了,果然做题是学习的好方法啊~~~~\(≧▽≦)/~啦啦啦,不过我们这组每次都是刚开始垫底,然后才慢慢追上去.......真担心爆零,但是结果还不错,和第一做的题目一样多,差的只是错误率和时间。

A:大意是:给你一个直线和一个弧线,(弧线是圆的一部分),求弧线高出直线的高度。POJ 1905   Expanding Rods

解法:先确定半径的范围再进行二分,r1=l/2,半径不可能再小了,再假设r2=l,求出所对应的弧长,若小于所给的长度,则取l,若大于,则r2=r2*2。再二分取对应的半径,最后带入,求高度差。注意!!!!!在这里半径越大,弧长反而越小!!!!!!还有c,n==0的时候要提出来讲,==0时,弧长=l,直接高度==0;

代码:    16MS

#include<stdio.h>

#include<iostream>

#include<algorithm>

#include<math.h>

using namespace std;

double l;

double f(double r)   //求弧长

{

    return (asin(l/r/2)*2*r);  //asin()是反三角函数

}

double g(double r) //求高度差

{

    return r-cos(asin(l/(r*2)))*r;

}

int main()

{

    double c;

    double n,r1,r2,mid,sum,w;

    while(~scanf("%lf%lf%lf",&l,&c,&n))

    {

        sum=l*(1+n*c);

        if(l<0&&c<0&&n<0)

            break;

        if(c==0||n==0)  //为零的时候要另外讲.......

            {

              printf("0.000\n");

              continue;

            }

        r1=l/2;   //半径不可能比l/2更小

        r2=l;

        while(f(r2)>=sum)//注意,半径越大,所对应的弧长越小......在这错了好久都没检查出来....

            r2=2*r2;

        while(f(r1)-f(r2)>1e-9)

        {

            mid=(r1+r2)/2;

            w=f(mid);

            if(w>sum)

                r1=mid;

            else if(w<sum)

                r2=mid;

            else if(w==sum)

                break;

        }

        printf("%.3lf\n",g(mid));

    }

    return 0;

}

B 大意是:给你n个点,找出任意4个点组合,有几个正方形   Squares

思路:先任意找两个点,确定一条边,确定一个正方形,再寻找另外两个点,若能找到则有正方形,计数+1。

代码:     1500MS

 1 #include <stdio.h>

 2 #include <string.h>

 3 #include<iostream>

 4 #include<algorithm>

 5 using namespace std;

 6 int n;    /* 点的个数 */

 7 struct Point

 8 {

 9     int x;

10     int y;

11 }point[1000];

12 bool comp1(Point i,Point j)

13 {

14     if(i.x<j.x)

15         return true;

16     else if(i.x==j.x)

17     {

18         if(i.y<j.y)

19             return true;

20     }

21     return false;

22 }

23 //由于点已经按照坐标排序过,所以采用二分查找

24 //搜索点(x,y)是否存在,存在返回1,否则返回0

25 int bsearch(int x, int y)

26 {

27     int m, s, t;

28     s = 0;

29     t = n-1;

30     while (s <= t)

31     {

32         m = (s+t)/2;

33         if (point[m].x == x && point[m].y == y) return 1;

34         if (point[m].x > x || (point[m].x == x && point[m].y > y))

35             t = m-1;

36         else

37             s = m+1;

38     }

39     return 0;

40 }

41 

42 int main()

43 {

44     int  x, y, i, j, count;

45     while (scanf("%d", &n), n)

46         {

47         count = 0;

48         for (i = 0; i < n; i++)

49             scanf("%d %d", &point[i].x, &point[i].y);

50             //插入法对点排序,按照x从小到大,y从小到大,且x优先排列的方式

51             // 枚举所有边,对每条边的两个顶点可以确定一个唯一的正方形,并求出另外两个顶点的坐标

52         sort(point,point+n,comp1);

53         for (i = 0; i < n; i++)

54             for (j = (i+1); j < n; j++)

55              {

56                 //计算第三个点的坐标,搜索其是否存在

57                 x = point[i].y-point[j].y+point[i].x;

58                 y = point[j].x-point[i].x+point[i].y;

59                 if (bsearch(x,y) == 0)

60                     continue;

61                 //计算第四个点的坐标,搜索其是否存在

62                 x = point[i].y-point[j].y+point[j].x;

63                 y = point[j].x-point[i].x+point[j].y;

64                 if (bsearch(x, y))

65                     count++;

66             }

67         printf("%d\n", count/2);

68     }

69     return 0;

70 }

 

C 大意是:有m个仓库,n头牛,要把牛放到仓库里,要使两两之间的距离尽可能的大,输出最小的距离。Aggressive cows

  不断假设满足的距离;

代码:       110MS

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<algorithm>

 4 using namespace std;

 5 int N,C,a[1000000];

 6 int juge(int m)

 7 {

 8     int number=1,i,frontt=0;

 9     for(i=0;i<N;i++)

10     {

11         if((a[i]-a[frontt])>=m)  //判断m是不是最小的距离

12         {

13             frontt=i;

14             number++;

15             if(number==C) return 1;//所有的牛都放进去了,满足

16         }

17     }

18     return 0;

19 }

20 

21 int main()

22 {

23     int i,midd,left,right;

24     scanf("%d%d",&N,&C);

25     for(i=0;i<N;i++)

26         scanf("%d",&a[i]);

27     sort(a,a+N);

28     left=0;

29     right=a[N-1]-a[0];

30     while(left<=right) //当l和r交叉错过时就跳出

31     {

32         midd=(left+right)/2;

33         if(juge(midd))

34             left=midd+1;//m可能小了

35         else

36             right=midd-1;  //m太大

37     }

38     printf("%d\n",left-1);

39     return 0;

40 }

D大意是:给出3个数组,从每个数组中挑一个出来加起来成一个数,问是否能组成所给的数。  Can you find it?

代码:    359MS,时限是3000MS

方法是合并a,b两个数组,变成了只有两个数组去凑数了。

 

 1 #include <stdio.h> 

 2 #include <iostream>

 3 #include <algorithm>

 4 using namespace std;

 5 int ab[280000],k;

 6 int f(int x)

 7 {

 8     int l=1,r=k,mid;

 9     while(l<=r)   //同C的判断方法一样 ,l,r错开就跳出

10     {

11         mid=(r+l)/2;

12         if(ab[mid]==x)

13             return 1;

14         if(ab[mid]<x)

15             l=mid+1;

16         else

17             r=mid-1;

18     }

19     return 0;

20 }

21 int main()

22 {

23     int l,m,n,i,j,o=1,s,w,a[505],b[505],c[505];

24     while(~scanf("%d%d%d",&l,&m,&n))

25     {

26         k=0;

27         for(i=0;i<l;scanf("%d",&a[i++]));

28         for(i=0;i<m;scanf("%d",&b[i++]));

29         for(i=0;i<n;scanf("%d",&c[i++]));

30         for(i=0;i<l;i++)

31             for(j=0;j<m;j++)

32             ab[k++]=a[i]+b[j];   //合并a,b两组数

33         sort(c,c+n);

34         sort(ab,ab+k);

35         for(printf("Case %d:\n",o++),scanf("%d",&s);s;s--)

36         {

37             scanf("%d",&w);

38             j=0;

39             for(i=0;i<n;i++)

40                 if(f(w-c[i]))

41             {

42                 j++;

43                 break;

44             }

45             if(j)

46                 printf("YES\n");

47             else

48                 printf("NO\n");

49         }

50     }

51     return 0;

52 }

E 大意是:给出一个方程:8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y,给出Y,要求求出X,给定X属于[0~100],如果不是在这个范围则输出No solution。

代码:   0MS     Can you solve this equation?

 1 #include<stdio.h>

 2 #include<math.h>

 3 int main()

 4 {

 5     int y,T;

 6     scanf("%d",&T);

 7     while(T--)

 8     {

 9         double  l=0,r=100,mid,sum;

10         scanf("%d",&y);

11         if(y<6||y>807020306)  //X小于0和大于100的情况,无解

12         {

13             printf("No solution!\n");

14             continue;

15         }

16         while(r-l>1e-9)

17         {

18             mid=(r+l)/2;  //二分

19             sum=pow(mid,4)*8+7*pow(mid,3)+mid*mid*2+3*mid+6;

20             if(sum>y)

21                 r=mid;

22             else if(sum<y)

23                 l=mid;

24             else if(sum==y)

25                 break;

26         }

27         printf("%.4lf\n",mid);

28     }

29     return 0;

30 }

F 大意是:F(x) = 6 * x^7+8*x^6+7*x^3+5*x^2-y*x (0 <= x <=100),这个方程,给出Y,求X使得F(X)的值最小,给出X的范围0~100。

思路,因为这不是个单调函数,所以要用三分做。     0MS     Strange fuction

 1 #include<iostream>

 2 #include<stdio.h>

 3 #include<algorithm>

 4 #include<math.h>

 5 using namespace std;

 6 double y;

 7 double dis(double x)

 8 {

 9     return 6*pow(x,7)+8*pow(x,6)+7*pow(x,3)+5*x*x-y*x;   //方程

10 }

11 int main()

12 {

13     double left,right,mid,mmid,t2,t1;

14     int t;

15     scanf("%d",&t);

16     while(t--)

17     {

18         mid=1;mmid=0;

19         scanf("%lf",&y);

20         left=0;right=100;

21         while(fabs(mid-mmid)>1e-9)

22         {

23             mid=left/2+right/2;  //三分

24             mmid=mid/2+right/2;

25             t2=dis(mid);t1=dis(mmid);

26             if(t2>t1)

27             {

28                 left=mid;

29             }

30             else if(t2<t1)

31             {

32                 right=mmid;

33             }

34             else

35                 break;

36         }

37         printf("%.4lf\n",t1);

38     }

39     return 0;

40 }

G 大意是:给出人在(0,0)这一点,目标在x,y,给出出箭的速度V,求能射到目标的最小角度   Toxophily  

有两种方法,一是用纯数学方法,二是用三分+二分。不过都先要找到x,y的关系式:x^2*g/(2*v^2)*tan^2(ß) - x*tan(ß) +y + x^2*g/(2*v^2) = 0;

先是第一种方法,把tanB看做未知数,就变成一个AX^2+BX+C=0的一元二次方程,当△<0时无解,输出-1,△=0时只有一个值,△>0时有两解,取>0,<90的解;取小得那个解。

代码:     0MS

 1 #include<iostream>   

 2 #include<stdio.h>

 3 #include<math.h>

 4 using namespace std;

 5 const double g=9.8;

 6 int main()

 7 {

 8     int t;

 9     double x,y,v,k,s,d;

10     cin>>t;

11     while(t--)

12         {

13         scanf("%lf%lf%lf",&x,&y,&v);

14         k=x*x-2*g*x*x/v/v*(y+0.5*g*x*x/v/v);   //

15         if(k<0)

16         {

17             printf("-1\n");

18         }

19         else

20         {

21             s =(x-sqrt(k))*v*v/g/x/x;  //小的根

22             if(s<0)

23                 s=(x+sqrt(k))*v*v/g/x/x;  //大的根

24             d=atan(s);    //反三角函数

25             printf("%.6lf\n",d);

26         }

27     }

28     return 0;

29 }

第二种方法:先用三分在0~90°之间找到最大值,如果最大值<y,则无解,输出-1,否则在0~t,之间二分,找到合适的角度。

代码来自:   http://blog.csdn.net/hello_there/article/details/8519008      0MS

 1 #include<iostream>

 2 #include<cstdio>

 3 #include<cmath>

 4 using namespace std;

 5 const double eps=1.0e-9;

 6 const double PI=acos(-1.0);

 7 const double g=9.8;

 8 double x,y,v;

 9 

10 double f(double t)

11 {

12     return x*tan(t)-g*x*x/2/(v*v*cos(t)*cos(t));

13 }

14 double two_devide(double low,double up)

15 {

16     double m;

17     while(up-low>=eps)

18     {

19         m=(up+low)/2;

20         if(f(m)<=y)

21             low=m;

22         else

23             up=m;

24     }

25     return m;

26 }

27 double three_devide(double low,double up)

28 {

29     double m1,m2;

30     while(up-low>=eps)

31     {

32         m1=low+(up-low)/3;

33         m2=up-(up-low)/3;

34         if(f(m1)<=f(m2))

35             low=m1;

36         else

37             up=m2;

38     }

39     return (m1+m2)/2;

40 }

41 int main()

42 {

43     int t;

44     double maxt;

45     cin>>t;

46     while(t--)

47     {

48         cin>>x>>y>>v;

49         maxt=three_devide(0,PI/2);

50         if(f(maxt)<y)

51             printf("-1\n");

52         else

53             printf("%.6lf\n",two_devide(0,maxt));

54     }

55     return 0;

56 }

H大意是:有n个精灵,要去同一个地方开会,他的不高兴程度=S^3*W,S,要走的距离,W,他的体重。求最小的不高兴的和。因为不确定函数的单调性,所以用三分。

代码:     Party All the Time

 1 #include<iostream>

 2 #include<algorithm>

 3 #include<stdio.h>

 4 #include<math.h>

 5 using namespace std;

 6 struct line

 7 {

 8     double bumanyi;   //体重

 9     double area;      //所在的位置

10 }a[50000];

11 bool comp1(line x,line y)

12 {

13     return x.area<y.area;

14 }

15 int main()

16 {

17     double mid,mmid,left,right,t1,t2;

18     int t,i,n,w=0;

19     scanf("%d",&t);

20     while(t--)

21     {

22         w++;

23         mid=1;mmid=0;

24         scanf("%d",&n);

25         for(i=0;i<n;i++)

26             scanf("%lf %lf",&a[i].area,&a[i].bumanyi);

27         sort(a,a+n,comp1);   //排序

28         left=a[0].area;

29         right=a[n-1].area;   //范围

30         while(fabs(mid-mmid)>1e-5)

31         {

32             t1=0;t2=0;

33             mid=left/2+right/2;   //三分

34             mmid=mid/2+right/2;

35             for(i=0;i<n;i++)

36             {

37                 t1+=fabs((a[i].area-mid)*(a[i].area-mid)*(a[i].area-mid))*a[i].bumanyi;

38                 t2+=fabs((a[i].area-mmid)*(a[i].area-mmid)*(a[i].area-mmid))*a[i].bumanyi;

39             }

40             if(t1>t2)

41                 left=mid;

42             else if(t1<t2)

43                 right=mmid;

44             else

45                 break;

46 

47         }

48         printf("Case #%d: %.lf\n",w,t1);

49     }

50     return 0;

51 }

不过这题的时限是2000MS,这个代码却用了1656,再在网上找个优化的代码。

网上的代码:531MS    其实只是把求和那用了个函数,时间就只有1/3........

 1 #include<stdio.h>

 2 #include<string.h>

 3 #include<stdlib.h>

 4 double ab(double x)

 5 {

 6     return x>0?x:-x;

 7 }

 8 struct node

 9 {

10     double x;

11     double w;

12 }q[50005];

13 int n;

14 double cal(double xi)

15 {

16     int i;

17     double res=0;

18     for(i=0;i<n;i++)

19     {

20         double t=ab(q[i].x-xi);

21         res+=t*t*t*q[i].w;

22     }

23     return res;

24 }

25 int main()

26 {

27     int ca=1,i,t;

28     double l,r,m,mm,ans;

29     scanf("%d",&t);

30     while(t--)

31     {

32         scanf("%d",&n);

33         for(i=0;i<n;i++)

34             scanf("%lf%lf",&q[i].x,&q[i].w);

35         l=q[0].x;

36         r=q[n-1].x;

37         while(l<r)

38         {

39             if(ab(r-l)<=0.001)

40                 break;

41             m=(l+r)/2;

42             mm=(m+r)/2;

43             if(cal(m)<cal(mm)) 

44             {

45                 ans=cal(m);

46                 r=mm;

47             }

48             else l=m;

49         }

50         printf("Case #%d: ",ca++);

51         printf("%.0lf\n",ans);

52     }

53     return 0;

54 }

 

你可能感兴趣的:(二分)