二分法入门(二)——POJ 3258,2976;HDU 4430;CodeForces 535C;Gym 101194D;ACdream 1066

来源:互联网 发布:历史api数据后原油波动 编辑:程序博客网 时间:2024/06/04 21:28

1.Bet ACdream - 1066


题意就是每次赌博有不同的可以买(买大买小这样的),每种有自己的赔率(赢了的回报为投入的钱y*回报率a[i]),每次赌博只能有一种是有回报的,要你求出最坏情况回报最大的值,策略就是把总金额y分成y[1],y[2],y[3]….使得y[1]*a[1]==y[2]*a[2]==……这样不论是哪一种获得回报你都会得到相同的回报,二分答案,然后判断钱能不能这样买。


#include<stdio.h>#include<algorithm>#include<iostream>using namespace std;double r,l,mid;int n;double money;double c[105];int main(){    while(~scanf("%d",&n)){        for(int i=0;i<n;i++){scanf("%lf",&c[i]);}        scanf("%lf",&money);        l=0,r=100000;        while(r-l>0.00001){            mid=(l+r)/2;            double cnt=0;            for(int i=0;i<n;i++){                cnt+=mid/c[i];            }            if(cnt>money){r=mid;}            else{l=mid;}        }        printf("%.2lf\n",mid);    }    return 0;}

River Hopscotch POJ - 3258

最大化最小值,二分题里很经典的一种了,跳石子,删去一些石子使得跳跃距离的最小值最大,最后一块不能删(起点和终点)。

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<iostream>using namespace std;int l,n,m;int lef,righ,mid;int a[50050];int main(){    while(~scanf("%d%d%d",&l,&n,&m)){        lef=0,righ=1000000001;        for(int i=00;i<n;i++){            scanf("%d",&a[i]);        }        a[n]=l;        sort(a,a+n+1);        while(righ-lef>1){            int mid=(righ+lef)/2;            int cnt=0,used=0;            bool yes=1;            for(int i=0;i<=n;i++){                if(a[i]-cnt<mid){                    if(i==n||used==m){yes=0;break;}                    else{used++;}                }                else{cnt=a[i];}            }            if(yes){lef=mid;}            else{righ=mid;}        }        printf("%d\n",lef);    }    return 0;}

Dropping tests POJ - 2976

之前写过很类似的题,最大化平均值,通常策略就是二分答案再依据答案排序贪心选择,判断能不能满足mid。

#include<stdio.h>#include<string.h>#include<algorithm>#include<string>#include<iostream>using namespace std;int n,m;double lef,righ,mid;int a[1005],b[1005];double c[1005];bool cmp(double a,double b){return a>b;}int main(){    while(scanf("%d%d",&n,&m),m+n){        m=n-m;        lef=0,righ=100;        for(int i=0;i<n;i++){            scanf("%d",&a[i]);        }        for(int i=0;i<n;i++){            scanf("%d",&b[i]);        }        for(int k=0;k<100;k++){            mid=(righ+lef)/2;            for(int i=0;i<n;i++){                c[i]=(double)a[i]*1.0*100-(double)b[i]*1.0*mid;            }            sort(c,c+n,cmp);            double cnt=0;            for(int i=0;i<m;i++){                cnt+=c[i];            }            if(cnt>=0){lef=mid;}            else{righ=mid;}        }        printf("%.0lf\n",mid);    }    return 0;}

Yukari’s Birthday HDU - 4430

以同心圆的方式给生日蛋糕插蜡烛,总共r圈,最内圈为b支蜡烛的情况下,第i圈插的蜡烛的数量为b^i,数量不能多也不能少,圆心可以插一根蜡烛也可以不插,求r*b的最小值。

因为蜡烛每一圈数量增长的速度非常快,所以r到50就足够满足数据范围了,枚举r然后寻找对应的b的最小值就行。

#include<iostream>#include<string.h>#include<stdio.h>#include<string>#include<vector>#include<algorithm>#include<queue>using namespace std;long long n;long long r, lk, rk, midk;int main(){    while (cin >> n){        n;        long long ss = n - 1, a_r = 1, a_k = n - 1;        for (int r = 2; r <= 50 && r <= n; r++){            lk = 1; rk = 1000001;            bool yes = 0;            while (rk - lk > 1){                midk = (rk + lk) / 2;                long long cnt = 1;                long long ans = 0;                for (int i = 1; i <= r; i++){                    ans += (cnt *= midk);                    if (ans > n)break;                }                if (ans == n || ans == n - 1){                    yes=1; rk = midk; break;                }                if (ans > n){ rk = midk; }                else{ lk = midk; }            }            if (yes){                if (r*rk < ss || (r*rk == ss&&r < a_r)){ ss = r*rk; a_r = r; a_k = rk; }            }        }        cout << a_r << " " << a_k << endl;    }    return 0;}

Tavas and Karafs CodeForces - 535C

#include<iostream>#include<stdio.h>#include<algorithm>using namespace std;long long A, B, n;long long l, t, m;int main(){    while (cin>>A>>B>>n){        for (int k = 0; k < n; k++){            cin >> l >> t >> m;            if (t < (A + (l - 1)*B)){ printf("-1\n"); }            else{                long long beg = l, endd = (t - A) / B + 2;                while (endd - beg>1){                    long long mid = (beg + endd) / 2;                    long long cnt = m*t;                    long long sss = ((A + (l - 1)*B) + (A + (mid - 1)*B))*(mid - l + 1) / 2;                    if (cnt >= sss){ beg = mid; }                    else{ endd = mid; }                }                printf("%d\n", beg);            }        }    }    return 0;}

Ice Cream Tower Gym - 101194D

构造冰淇凌塔需要下面一块是上面的两倍以上,给出n个冰淇凌球,要求塔高为k,问能构造出多少个冰淇凌塔,排序,二分可以构造出来的数量,然后贪心判断结果,我用的优先队列,先把前mid个球加入队列作为mid个塔的顶,然后顺序遍历数组,每次就与优先队列的top(塔高最小且最下面的球的面积最小)的比较能否满足,满足就pop队列顶然后push({s,h+1})进去,这是一种比较直观的做法,但是跑出来时间有点久,其实判断满足mid的时候也可以lower_bound当前球两杯大小来寻找,速度更快。

#include<iostream>#include<string.h>#include<stdio.h>#include<string>#include<algorithm>#include<queue>using namespace std;int n, k;long long b[300005];struct ice{    long long maxn;    int h;    bool operator <(const ice b)const{        if (h == b.h){ return maxn>b.maxn; }        return h > b.h;    }};priority_queue<ice> que;int main(){    int t;    scanf("%d", &t);    for(int cas=1;cas<=t;cas++){        //cin >> n >> k;        scanf("%d%d", &n, &k);        for (int i = 0; i < n; i++){            cin >> b[i];            //scanf("%lld", &b[i]);        }        sort(b, b + n);        int beg = 0, endd = n / k+3;        while (endd - beg>1){            int mid = (endd + beg) / 2;//totalnum            for (int i = 0; i < mid&&i<n; i++){                que.push({ b[i], 1 });            }            for (int i = mid; i < n; i++){                ice cnt = que.top();                if (b[i] >= 2 * cnt.maxn){                    que.pop();                    que.push({ b[i], cnt.h + 1 });                }            }            int total = 0;            while (!que.empty()){                if (que.top().h >= k)total++;                que.pop();            }            if (total < mid){ endd = mid; }            else{ beg = mid; }        }        cout << "Case #" << cas << ": " << beg << endl;    }    return 0;}
0 0