zoukankan      html  css  js  c++  java
  • 第二次组队赛 二分&三分全场

    网址: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
    ");
                  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
    ",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
    ", 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
    ",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:
    ",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
    ");
    47             else
    48                 printf("NO
    ");
    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!
    ");
    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
    ",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
    ",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
    ");
    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
    ",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
    ");
    52         else
    53             printf("%.6lf
    ",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
    ",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
    ",ans);
    52     }
    53     return 0;
    54 }
  • 相关阅读:
    Cassandra key说明——Cassandra 整体数据可以理解成一个巨大的嵌套的Map Map<RowKey, SortedMap<ColumnKey, ColumnValue>>
    Cassandra二级索引原理——新创建了一张表格,同时将原始表格之中的索引字段作为新索引表的Primary Key,并且存储的值为原始数据的Primary Key,然后再通过pk一级索引找到真正的值
    Cassandra 的数据存储结构——本质是SortedMap<RowKey, SortedMap<ColumnKey, ColumnValue>>
    Cassandra 单机入门例子——有索引
    cassandra框架模型之二——存储机制 CommitLog MemTable SSTable
    cassandra框架模型之一——Colum排序,分区策略 Token,Partitioner bloom-filter,HASH
    elasticsearch负载均衡节点——客户端节点 node.master: false node.data: false 其他配置和master 数据节点一样
    Elasticsearch压缩索引——lucene倒排索引本质是列存储+使用嵌套文档可以大幅度提高压缩率
    elasticsearch 2.2+ index.codec: best_compression启用压缩
    一些开源搜索引擎实现——倒排使用原始文件,列存储Hbase,KV store如levelDB、mongoDB、redis,以及SQL的,如sqlite或者xxSQL
  • 原文地址:https://www.cnblogs.com/riddle/p/3226471.html
Copyright © 2011-2022 走看看