这次的比赛是二分&三分专题,说实话以前都没有接触过二分,就在比赛前听渊神略讲了下.......不过做着做着就对二分熟悉了,果然做题是学习的好方法啊~~~~\(≧▽≦)/~啦啦啦,不过我们这组每次都是刚开始垫底,然后才慢慢追上去.......真担心爆零,但是结果还不错,和第一做的题目一样多,差的只是错误率和时间。
A:大意是:给你一个直线和一个弧线,(弧线是圆的一部分),求弧线高出直线的高度。 Expanding Rods
代码: 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,他的体重。求最小的不高兴的和。因为不确定函数的单调性,所以用三分。
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 }