二分法入门(二)——POJ 3258,2976;HDU 4430;CodeForces 535C;Gym 101194D;ACdream 1066
2017-02-19 11:28
459 查看
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 =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; }
相关文章推荐
- hdu 2222(ac自动机入门题)
- HDU 2222 Keywords Search(AC自动机的入门题)
- 哈希表入门题目总结(HDU 1280、1425、2027、3833、1496、2648 POJ 1200)
- 概率DP求期望入门,HDU 4405,POj 2096,HDU 3853
- poj 3258 二分法求最小值最大
- hdu 2222 Keywords Search(AC自动机入门题)
- hdu 1162 Eddy's picture 最小生成树入门题 Prim+Kruskal两种算法AC
- hdu 2222 Keywords Search(AC自动机入门题)
- HDU 2222 Keywords Search (AC 自动机入门)
- NYOJ 323 && HDU 1532 && POJ 1273 Drainage Ditches (网络流之最大流入门)
- HDU 2222 Keywords Search (AC自动机入门题)
- POJ 2976 0-1分数规划入门
- 01 分数规划 poj 2976 利用二分法即可
- 插头DP——从不会到入门(POJ 2411,HDU 1565,HDU 2167,HDU 1693,Ural 1519)
- POJ 1273 || HDU 1532 Drainage Ditches ,最大流入门题
- HDU 2037 今年暑假不AC (贪心入门)
- hdu 2037 今年暑假不AC【贪心入门题目】
- hdu2222之AC自动机入门
- HDU 2222 Keywords Search(AC自动机入门题)
- hdu 1863 畅通工程 最小生成树模板入门题 prim+kruskal两种算法AC。