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

网址: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 }

 

posted @ 2013-07-30 20:43  荆红浅醉  阅读(193)  评论(0编辑  收藏  举报