2014年暑假培训 - 二分三分

来源:互联网 发布:大学生借钱的软件 编辑:程序博客网 时间:2024/06/03 00:37

挂题网站:http://vjudge.net/contest/view.action?cid=49719#overview

A - Light Bulb

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3203

/*当人正好贴墙站着的时候,此时影子的长度等于人的身高h;当人的影子正好投到水平线D的最右边时,即影子都在水平线上,

墙上没投影。相似得出二分区间为[ D - D * h / H , D ]。再由相似可得L = D + H - X + D * (h - H)  /  X , 因为这是一个开口向下

的抛物线,所以如果cal(mid) >= cal(midmid)的话,把right更新为midmid;反之,如果 cal(mid) < cal(midmid)的话,把left更

新为mid,用d1和d2来分别保存cal(mid)和cal(midmid)的值。*/

AC代码:

#include <iostream>#include <cstdio>using namespace std;double H, h, D;double mid , midmid;double calc(double x){    return D - x + H - (H - h) * D / x;}double solve(double left , double right){    double d1,d2;    while(right - left > 1e-9)    {        mid = (left + right) / 2;        midmid = (mid + right) / 2;        d1 =  calc(mid);        d2 = calc(midmid);        if(d1 >= d2)            right = midmid;        else            left = mid;    }    return d1;}int main(){//freopen("in.txt","r",stdin);    int T;    scanf("%d",&T);    while(T--)    {        scanf("%lf%lf%lf",&H,&h,&D);        printf("%.3lf\n",solve( (H - h) * D / H , D ) );    }}



B - Turn the corner

acm.hdu.edu.cn/showproblem.php?pid=2438

/*推导出s = l * cos(x) + w * sin(x) - x ;  h = s * tan(x) + w * cos(x); */

AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#include <string>#include <vector>#include <list>#include <map>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <numeric>#include <functional>using namespace std;double x , y , l , d;const double PI = acos(-1.0);double mid , midmid;double cal(double key){    double s = l * cos(key) + d * sin(key) - x;    double h = s * tan(key) + d * cos(key);    return h;}int main(){   // #ifndef DoubleQ   // freopen("in.txt","r",stdin);  //  #endif    while(~scanf("%lf%lf%lf%lf",&x,&y,&l,&d))    {        double left = 0.0;        double right = PI / 2;        while((right - left) > 1e-12)        {            mid = (left + right) / 2;            midmid = (mid + right) / 2;            if(cal(mid) >= cal(midmid))                right = midmid;            else                left = mid;        }        if(cal(mid) <= y)            printf("yes\n");        else            printf("no\n");    }}




C - The Moving Points

http://acm.hdu.edu.cn/showproblem.php?pid=4717


AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#include <string>#include <vector>#include <list>#include <map>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <numeric>#include <functional>using namespace std;#define N 400struct node{    double x , y , vx, vy;}e[N];double mid , midmid;int n;double dis(node a, node b, double key){    return sqrt( (a.x + a.vx * key - b.x - b.vx * key) * (a.x + a.vx * key - b.x - b.vx * key) +                (a.y + a.vy * key - b.y -b.vy * key) * (a.y + a.vy * key - b.y -b.vy * key) );}double cal(double key){    double ans = 0;    for(int i = 0 ; i < n ;i ++)    {        for(int j = i + 1 ; j < n ; j ++)        {            ans = max(ans , dis(e[i] , e[j] , key));        }    }    return ans;}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    int T;    scanf("%d",&T);    int cnt = 1;    while(T--)    {        scanf("%d",&n);        for(int i = 0 ; i < n ; i ++)            scanf("%lf%lf%lf%lf\n", &e[i].x , &e[i].y , &e[i].vx , &e[i].vy);        double left = 0.0;        double right = 10000000;        while((right - left) > 1e-10)        {            mid = (left + right) / 2.0;            midmid = (mid + right) / 2.0;            if(cal(mid) < cal(midmid))                right = midmid;            else                left = mid;        }        printf("Case #%d: %.2lf %.2lf\n", cnt , mid , cal(mid));        cnt++;    }}


D - Solve this equation

http://acm.hdu.edu.cn/showproblem.php?pid=2199


/*首先明确如果Y的值不在f(0.0)~f(100.0)之间的话,一定是没解的,输出“No solution!”;否则在[ 0.0 , 100.0]间二分,

这是一个开口向上的抛物线,如果f(mid) < y的话,把left更新为mid;反之把right更新为mid.*/


AC代码:

#include <iostream>#include <cstdio>#include <cmath>using namespace std;double y;double mid;double f(double x){    return 8 * pow(x , 4) + 7 * pow(x , 3) + 2 * pow(x , 2) + 3 * x + 6 ;}int main(){//freopen("in.txt","r",stdin);    int T;    scanf("%d",&T);    while(T--)    {        scanf("%lf",&y);        if(f(0.0) > y || f(100.0) < y)        {            printf("No solution!\n");            continue;        }        double left = 0.0;        double right = 100.0;        while((right - left) > 1e-8)        {            mid = (left + right) / 2.0;            if( f(mid) < y )                left = mid ;            else                right = mid ;        }        printf("%.4lf\n",mid);    }}



E - UmBasketella

http://poj.org/problem?id=3737


/*运用强大的数学知识,有时候可以节省不少代码量。

(1)圆锥表面积公式:S  = PI *  r * l + PI * r * r ;

(2)母线公式: l = sqrt( r *  r + h * h ) ;

(1)与(2)联立得  (3) r * r = s * s / ( PI * PI  * h * h + 2 * PI * S ) ;

(4)圆锥体积公式: V = PI * r * r * h / 3 ;

(3) 和(4)联立得(5) V = h * s * s / (3 * PI * h * h + 6 * s) ;

对(5)求一阶导,另一阶导得0,最后得出:

r = sqrt(s/PI)/2;h = sqrt((s*s)/(PI*PI*r*r) - 2*s/PI);v = PI*r*r*h/3;


AC代码:

#include<iostream>#include<cmath>#include <cstdio>using namespace std;const double PI = acos(-1.0);int main(){    //freopen("in.txt","r",stdin);    double s, r, h, v;    while(scanf("%lf", &s) != EOF)    {        r = sqrt(s/PI)/2;        h = sqrt((s*s)/(PI*PI*r*r) - 2*s/PI);        v = PI*r*r*h/3;        printf("%.2lf\n%.2lf\n%.2lf\n", v, h, r);    }    return 0;}





F - Party All the Time

http://acm.hdu.edu.cn/showproblem.php?pid=4355

/*抽象为一个坐标系里一大堆散列的点,求某点到其余各点距离和最小的距离和*/

AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <cmath>#include <string>#include <vector>#include <list>#include <map>#include <queue>#include <stack>#include <bitset>#include <algorithm>#include <numeric>#include <functional>using namespace std;int n;double mid , midmid;double d1 , d2;struct node{    double x , w;}e[50005];double cal(double key){    double sum = 0;    for(int i = 0; i < n ; i ++)    {        double k = e[i].x - key;        if(k < 0)   k *= -1;        sum += k * k * k * e[i].w;    }       // sum += fabs(e[i].x - key) * fabs(e[i].x - key) * fabs(e[i].x - key) * e[i].w;    return sum;}int main(){    #ifdef DoubleQ    freopen("in.txt","r",stdin);    #endif    int T;    scanf("%d",&T);    int cas = 1;    while(T--)    {        scanf("%d",&n);        double left = 1000000 , right = -1000000;        for(int i = 0 ; i < n ; i ++)        {            scanf("%lf%lf",&e[i].x , &e[i].w);            left = min(left , e[i].x);            right = max(right , e[i].x);        }        double k = right -left;        while(k >= 1e-7)        {            mid = (right + left) / 2;            midmid = (mid + right) / 2;            d1 = cal(mid);            d2 = cal(midmid);            if(d1 < d2)                right = midmid;            else                left = mid;            k = right -left;        }        printf("Case #%d: %.0lf\n",cas , d1);        cas++;    }}



H - The Frog's Games

http://acm.hdu.edu.cn/showproblem.php?pid=4004

/*输入完距离后排下序,然后求出最大距离差maxs,然后在maxs和河宽l间二分枚举*/

AC代码:

#include <iostream>#include <cstdio>#include <cmath>#include <algorithm>using namespace std;int l, m;int n;int mid;int a[10000010];int sum;int maxs;int ans;bool check(int key){    int cnt = 0 ;    int s = 0;    if(key < maxs)   return false;    for(int i = 0 ; i < n; i++)    {        if(s + key >= a[i] && key + s < a[i+1])        {            cnt ++ ;            s = a[i];        }    }    cnt++;    if(cnt <= m)        return true;    else        return false;}int main(){//freopen("in.txt","r",stdin);    while(~scanf("%d%d%d",&l,&n,&m))    {        for(int i = 0 ; i < n; i ++)            scanf("%d",&a[i]);        a[n] = l;        sort(a , a + n + 1);        maxs = a[0];        for(int i = 1 ; i  <= n ; i++)            maxs = max(maxs  , a[i] - a[i-1]);        int left = maxs, right = l;        while(left <= right)        {            mid = (left + right) / 2;            if(check(mid))            {                ans = mid;                right = mid - 1;            }            else                left = mid + 1;        }        printf("%d\n",ans);    }    return 0;}

0 0