二分。三分
https://vjudge.net/contest/271273#problem/A
哎,后面有个四舍五入的问题。
if( (int) (right * 1000) % 10 >= 5) right -= 0.005; printf("%.2f\n", right);
.2f是默认四舍五入的,上面一段代码是取消四舍五入。
https://vjudge.net/contest/271273#problem/M
https://vjudge.net/contest/271273#problem/J
三分
https://vjudge.net/contest/271273#problem/N
数学题,不会
https://cn.vjudge.net/contest/260332#status/xiayuyang/A
二分尺取
一般如果是那种求精度的,直接lb.ub = mid; ub - lb < 1ex;或者用for循环x次(一般为100,2的一百次方够了)
如果是那种求 lb < ub,这种要lb + 1, ub - 1;
最小值最大化的二分区间是右闭左开(L,R],每次二分的中心为M=(L+R+1)/2;最大值最小化的二分区间是左闭右开,[L,R),每次二分的中心为M=(L+R)/2。
因为。。。。
二分时间复杂度nlogn;
二分法:适用于单调函数,单调增或单调减
三分法:适用于单峰凸性函数,如二次函数,或者是要求两个点
http://www.cnblogs.com/xiaowuga/p/8609943.html
poj 3273 Monthly Expense 最小化最大值
题目意思:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxm = 1e5 + 5; int a[maxm]; int n, m; bool fun(int x, int val) { for(int i = 0; i < n; i++) { int res = a[i]; if(res <= x) { while(res <= x) { i++; res += a[i]; val--; if(i >= n) break; } val++; i--; // printf("vsdnvs\n"); } else { return false; } } if(val <= 0) return true; else return false; } int main() { scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) { scanf("%d", &a[i]); } int l = 0, r = 1e9, mid; while(l <= r) { mid = (l + r) / 2; if(fun(mid, n - m)) { r = mid - 1; } else { l = mid + 1; } } if(fun(l, n - m)) printf("%d\n", l); else if(fun(r, n - m)) printf("%d\n", r); //printf("%d\n", fun(500, n - m)); return 0; }
River Hopscotch 最大化最小值
牛过河,有很多石头,起点为1,终点为n,移去m快石头,求之后的最小值。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxm = 50010; int dis, n, m, a[maxm]; bool fun(int x, int val) { for(int i = 1; i <= n + 1; i++) { int res = a[i - 1]; if(a[i] - res < x) { while(a[i] - res < x) { i++; val--; if(i > n + 1) break; } } } if(val < 0) return false; else return true; } int main() { scanf("%d%d%d", &dis, &n, &m); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } a[n + 1] = dis; sort(a, a + 2 + n); int l = 0, r = 1e9, mid; while(l <= r) { mid = (l + r + 1) / 2; if(fun(mid, m)) { l = mid + 1; } else { r = mid - 1; } } if(fun(r, m)) printf("%d\n", r); else if(fun(l, m)) printf("%d\n", l); return 0; }
Flyer
HDU - 4768 想法二分,一些人给 学校所有人发传单,a,b,c,发给a + k* c;k大于等于0,序号不小于c,求拿到奇数的那个人。
n个社团派发传单,有a,b,c三个参数,派发的规则是,派发给序号为a,a+c....a+k*c,序号要求是小于等于b
这其中,有一个学生只收到了奇数传单,要求找出这个学生的编号与得到的传单数目
思路:如果使用异或运算,也还是比较简单的,但是这样的话所花费的时间就比较长,正确的做法是使用二分
使用二分来划分区间,由于是每个社团得到的序列都是等差数列,所以我们很容易能得到区间派发的传单数
如果是奇数,那么所求的人肯定在左区间,否则在右区间,这样二分下去找到答案
https://blog.csdn.net/libin56842/article/details/25741317
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxm = 2e4 + 5; ll n, A, B, C, a[maxm], b[maxm], c[maxm]; bool solve(ll d) { ll num = 0; for(int i = 0; i < n; i++) { if(d >= a[i]) { ll x = min(d, b[i]); num += (x - a[i]) / c[i] + 1; } } return num % 2; } ll check(ll d) { ll num = 0; for(int i = 0; i < n; i++) { if(d >= a[i] && d <= b[i]) { if( (d - a[i]) % c[i] == 0 ) num++; } } return num; } int main() { while(~scanf("%lld", &n)) { for(int i = 0; i < n; i++) { scanf("%lld%lld%lld", &a[i], &b[i], &c[i]); } ll lb = -1, ub = 1ll << 32, ans = 0; while(lb <= ub) { ll mid = (ub + lb) / 2; if(solve(mid)) { ub = mid - 1; ans = mid; } else lb = mid + 1; } if(check(ans) % 2) printf("%lld %lld\n", ans, check(ans)); else printf("DC Qiang is unhappy.\n"); } return 0; }
https://vjudge.net/contest/271273#problem/J
看一下代码 三分
A Star not a Tree? POJ - 2420
和poj1379差不多
很多个点,求一个点到所有点的距离之和最小。
#include<cstdio> #include<algorithm> #include<cmath> using namespace std; typedef pair<double, double> pii; pii p[105]; int n; double sum(double x, double y) { double num = 0; for(int i = 0; i < n; i++) { num += sqrt( (x - p[i].first) * (x - p[i].first) + (y - p[i].second) * (y - p[i].second) ); } return num; } double check(double d) { double lb = 0, ub = 10001; for(int i = 0; i < 100; i++) { double midy = (lb + ub) / 2.0; double midmidy = (midy + ub) / 2.0; if(sum(d, midy) < sum(d, midmidy)) { ub = midmidy; } else lb = midy; } return min(sum(d, ub), sum(d, lb)); } int main() { scanf("%d", &n); for(int i = 0; i < n; i++) { scanf("%lf%lf", &p[i].first, &p[i].second); } double lb = 0, ub = 10001; for(int i = 0; i < 100; i++) { double midx = (lb + ub) / 2.0; double midmidx = (midx + ub) / 2.0; if(check(midx) < check(midmidx)) { ub = midmidx; } else lb = midx; } printf("%.0f\n", min(check(lb), check(ub))); return 0; }
UmBasketella
已知圆锥面积求体积,高
公式:圆锥面积=PI * r * r + PI * r * l (l为母线长度)
l * l = h * h + r * r.
#include<iostream> #include<cstdio> #include<cmath> using namespace std; const double PI = acos(-1.0), eps = 1e-6; double s; double cal(double r) { double R = s/(PI*r) - r; double h = sqrt(R*R - r*r); return h*PI*r*r/3; } int main() { while(scanf("%lf", &s) != EOF) { double left = 0, right = sqrt(s/(2*PI)), v; while(right - left > eps) { double middle = (left + right) / 2; double middleright = (middle + right) / 2; double v1 = cal(middle); double v2 = cal(middleright); if(v1 >= v2) { right = middleright; v = v1; } else { left = middle; v = v2; } } double r = right; double H = sqrt((s/(PI*r) - r)* (s/(PI*r) - r) - r*r); printf("%.2f\n%.2f\n%.2f\n", v, H, r); } return 0; }
Light Bulb
数学题(主要是退公式) 精度尽量改小点。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int t; double D,H,h; double fun2(double x) { return D - x + H - (H - h) * D / x; } double fun(double l, double r) { double mid, midmid, res; while(r - l >= 1e-9) { mid =(l + r) / 2; midmid = (mid + r) / 2; double a = fun2(mid); double b = fun2(midmid); if(a < b) { l = mid; res = fun2(mid); } else { r = midmid; res = fun2(midmid); } } return res; } int main() { scanf("%d", &t); while(t--) { scanf("%lf%lf%lf", &H, &h, &D); printf("%.3f\n", fun((H - h) * D / H, D)); } return 0; }