7.30二分及三分(组队的)

Problem A POJ 1905  Expanding Rods (二分法)

题目大意就是说有一根细丝,在受热后会膨胀产生形变,变为一个圆弧,给出圆弧变化前后的长度,求这根细丝在水平上升高了多少

解题过程:由于题目呢给定了说形变不会是细丝变为超过一个半圆的形状,所以我们就可以对形变的高度二分假设升高了x,那么设圆的半径为R,就存在公式

                                R^2 - (R-x)^2 = (L/2)^2       其中L是细丝变化前的长度

解出来                       R = x/2 + (L*L)/(8*x);

然后可以求出圆心角      Sita = 2 * asin((L/2) / R);

在比较R*Sita与L1(形变后的长度)   其实这里我也没有证明它在0~(L/2)之间是严格递增或是严格递减的,反而证明出了在这个区间他是有增有减的,所以我很郁闷,暂且只能放在这里了,代码是直接二分给出的,我三分求最大值后,再在最小到最大值之间二分反而错了,实在是无解了,网大神指点

 1 #include <stdio.h>
 2 #include <math.h>
 3 
 4 const double eps1 = 1e-4;
 5 double L,L1,n,C;
 6 
 7 int main()
 8 {
 9     while(~scanf("%lf%lf%lf", &L, &n, &C) && (L!=-1))
10     {
11         if(!L || !n || !C) {printf("0.000\n"); continue;}
12         L1 = L * (1 + n * C);
13         double l = 0, r = L/2,mid,R,Sita;
14         while(r-l>eps1)
15         {
16             mid = (l+r)/2;
17             R = mid/2 + L*L/mid/8;
18             Sita = 2 * asin(L/2/R);
19             if(Sita * R > L1) r = mid;
20             else l = mid;
21         }
22         printf("%.3lf\n", mid);
23     }
24     return 0;
25 }

 

 

Problem B POJ 2002 Squares

还没有搞出

 

 

Problem C POJ 2456  Aggressive cows

题目大意是说给出n个牛棚和m头牛,目标是将m头牛放进n个牛棚中去,且要让他们两两之间的距离尽量大,求这时最小的两个有牛的牛棚之间的距离

目标是要让有牛的牛棚之间的距离尽量大,且那时距离最小的两个牛棚之间的距离,那我们就可以直接二分这个最小距离,如果当前这个最小距离可以满足把所有的牛全部放进去,而且还有多的牛棚,那就二分他与最大值之间的距离,否则二分他与最小值之间的中点

以下是章爷的代码

 1         #include <iostream>
 2         #include <cstdio>
 3         #include <cstring>
 4         #include <queue>
 5         #include <algorithm>
 6         #include <cmath>
 7         #include <stack>
 8         #define LL long long
 9         using namespace std;
10         const int inf=0x3f3f3f3f;
11         const int maxn=100000+10;
12         int x[maxn],c,n;
13         int judge(int val)
14         {
15             int i,sum=1,cur=0;
16             for(i=1;i<n;i++)
17             {
18                 if(sum==c) break;
19                 if(cur+x[i]>=val)
20                 {
21                     sum++;
22                     cur=0;
23                 }
24                 else cur+=x[i];
25             }
26             if(sum==c) return 1;
27             else return 0;
28         }
29         int main()
30         {
31             cin>>n>>c;
32             int i;
33             for(i=0;i<n;i++) scanf("%d",&x[i]);
34             sort(x,x+n);
35             for(i=n-1;i>=1;i--) x[i]=x[i]-x[i-1];
36             int low=0,high=1000000001,mid;
37             while(high>low)
38             {
39                 mid=low+(high-low)/2;
40                 if(judge(mid)) low=mid+1;
41                 else high=mid;
42             }
43             printf("%d\n",low-1);
44             return 0;
45         }

 

Problem D HDU 2141 Can you find it?

题目是说给出一系列的A,B和C,以及一些和sum,要你对每一个sum从A,B和C数组中分别找出一个使他们的和为当前这个sum,最开始做的时候哦直接枚举A和B,然后用sum减去每一个C,再二分这个数组,居然发现超时了。

仔细一分析,有1000个sum,500个A,500个B,再加上二分sum-C,时间复杂度就是O(1000 * 500 * 500 * log500),明显超时了,后来章爷突发灵感,吧A+B保存起来,再对每一个sum-C数组,二分A+B这样复杂度就是O(1000 * 500 * log250000),可以过了,挂拉呱啦敲完了,过了!!!膜拜章爷啊啊啊~~~

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 
 5 int a[505],b[505],c[505],ab[250005];
 6 int A,B,C,AB,X,S;
 7 
 8 int find_AB(int sum)
 9 {
10     int l=0,r=AB-1;
11     while(l<=r)
12     {
13         int x=(l+r)>>1;
14         if(sum == ab[x]) return 1;
15         else if(sum < ab[x]) r = x-1;
16         else l=x+1;
17     }
18     return 0;
19 }
20 
21 
22 int main()
23 {
24     int Case=1;
25     while(~scanf("%d%d%d",&A, &B, &C))
26     {
27         for(int i=0;i<A;i++)
28         {
29             scanf("%d", &a[i]);
30         }
31         AB = 0;
32         for(int i=0;i<B;i++)
33         {
34             scanf("%d", &b[i]);
35             for(int j=0;j<A;j++)
36             {
37                 ab[AB++] = b[i]+a[j];
38             }
39         }
40         sort(ab,ab+AB);
41         for(int i=0;i<C;i++)
42         {
43             scanf("%d", &c[i]);
44         }
45         printf("Case %d:\n", Case++);
46         scanf("%d", &S);
47         for(int i=0;i<S;i++)
48         {
49            scanf("%d", &X);
50            int ans =0;
51            for(int j=0;j<C && !ans;j++)
52            {
53                ans=find_AB(X-c[j]);
54            }
55            printf("%s\n", ans == 0?"NO":"YES");
56         }
57     }
58     return 0;
59 }

 

 

Problem E HDU 2199  Can you solve this equation? 简单的二分

 1 #include <stdio.h>
 2 #include <math.h>
 3 #define eps 1e-10
 4 
 5 double f(double x)
 6 {
 7     return 8*pow(x,(double)4) + 7*pow(x,(double)3) + 2*pow(x,(double)2) + 3*x + 6;
 8 }
 9 
10 int main()
11 {
12     int T;
13     while(~scanf("%d", &T))while(T--)
14     {
15         double l = 0, r = 100, x, y;
16         scanf("%lf", &y);
17         if(y<6 || f(100)<y){printf("No solution!\n");continue;}
18         while(l+eps<r)
19         {
20             x = (r+l)/2;
21             double a = f(x);
22             if(a+eps < y)l=x;
23             else if(a-eps > y)r = x;
24             else break;
25         }
26         printf("%.4lf\n", x);
27     }
28     return 0;
29 }

 

 

Problem F HDU 2899 Strange fuction

求函数的最小值,就只需要将方程求导,倒数为0的点就是所求,接下来就是同上了

 1 #include <stdio.h>
 2 #include <math.h>
 3 #define eps 1e-10
 4 
 5 double x,y;
 6 
 7 double f(double x)
 8 {
 9     return 42*pow(x,(double)6) + 48*pow(x,(double)5) + 21*pow(x,(double)2) + 10*x ;
10 }
11 
12 double g(double x)
13 {
14     return 6 * pow(x,7)+ 8*pow(x,6) + 7*pow(x,3) + 5*pow(x,2) - y*x;
15 }
16 
17 int main()
18 {
19     int T;
20     while(~scanf("%d", &T))while(T--)
21     {
22         double l = 0, r = 100;
23         scanf("%lf", &y);
24         if(y<6 || f(100)<y){printf("No solution!\n");continue;}
25         while(l+eps<r)
26         {
27             x = (r+l)/2;
28             double a = f(x);
29             if(a+eps < y)l=x;
30             else if(a-eps > y)r = x;
31             else break;
32         }
33         printf("%.4lf\n", g(x));
34     }
35     return 0;
36 }

 

 

Problem G HDU 2298  Toxophily

这道题要求从0 0 打到x y已知初速度的最小出射角度,我的方法是按照公式

y = Vsin(Sita)*t - G*t^2/2和

x = Vcos(Sita)*t;

对于已知可以达到x求出可以达到最高的y的角度,再在0到这个范围二分

之所以要求出到达x时所能到达的最高高度,是由于将t消去(下面的式子代入上式)后,y不是单调函数而是先增后减,而题目又是要求最小的出射角,那我们必然可以求出最大高度时的角度,那么角度在0到这个范围中一定有一个是原来的解,二分即可

 1 #include <stdio.h>
 2 #include <math.h>
 3 const double eps = 1e-10;
 4 const double eps1 = 1e-7;
 5 const double pi = 4 * atan(1.0);
 6 const double G = 9.8;
 7 double V, x, y;
 8 
 9 
10 double f(double sita)
11 {
12     return V*sin(sita)*x/(V*cos(sita)) - (G*x*x)  /  ( 2 * V * V * (cos(sita) * cos(sita))  ) ;
13 }
14 
15 int main()
16 {
17     int T;
18     while(~scanf("%d", &T))while(T--)
19     {
20         scanf("%lf %lf %lf", &x, &y, &V);
21 
22         if(x==0 && (V*V/(2*G)-y) > eps ){printf("%lf\n",pi/2); continue;}
23         else if(x==0 && (y - V*V/(2*G))>eps ){printf("-1\n"); continue;}
24 
25         double  l = 0, r = pi/2+0.5;
26         double mid = 0, midmid = pi/2;
27         while(midmid - mid > eps)
28         {
29             mid = (l+r)/2;
30             midmid = (mid+r)/2;
31             double mid_val = f(mid);
32             double midmid_val = f(midmid);
33             if(midmid_val < mid_val)   r = midmid;
34             else l = mid;
35         }
36         if(y > f(mid)){printf("-1\n"); continue;}
37         double ans = 0;
38         l = 0, r = mid;
39         while(1)
40         {
41             mid = (l+r)/2;
42             double temp = f(mid);
43             if(fabs(y - temp) < eps1){ans = mid;break;}
44             else if(temp < y)  l = mid;
45             else r = mid;
46         }
47         printf("%lf\n", ans);
48     }
49     return 0;
50 }

 

Problem H HDU 4355  Party All the Time

暂未搞出

 

posted @ 2013-08-03 00:47  再见~雨泉  阅读(265)  评论(0编辑  收藏  举报