[Uva Error Curves]一些二次函数取max的交集还是一个下凸函数。三分即可
#include <bits/stdc++.h>
#define maxn 10010
using namespace std;
int n, a[maxn], b[maxn], c[maxn];
#define F(i, x) a[i] * x * x + b[i] * x + c[i]
inline double cal(double x){
double ret = -1e12;
for(int i = 1; i <= n; i ++)
ret = max(ret, F(i, x));
return ret;
}
inline void solve(){
double l = 0, r = 1000;
for(int i = 1; i <= 300; i ++){
double len = (r - l) / 3;
double m1 = l + len, m2 = r - len;
if(cal(m1) < cal(m2))r = m2;
else l = m1;
}
printf("%.4lf\n", cal(l));
}
int main(){
int test;
scanf("%d", &test);
while(test --){
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%d%d%d", &a[i], &b[i], &c[i]);
solve();
}
return 0;
}
[Zoj Light Bulb]列出数学式子,是一个对勾函数(可以直接解),或者三分,注意影子到地上的判断,不过D-x≤H??
#include <bits/stdc++.h>
using namespace std;
double H, h, D, P, Q;
inline double check(double x){
return -x + P / x + Q;
}
void solve(){
P = D * (h - H), Q = D + H;
double l = 1e-9, r = min(H, D);
for(int i = 1; i <= 1000; i ++){
double len = (r - l) / 3;
double m1 = l + len, m2 = r - len;
if(check(m1) > check(m2))r = m2;
else l = m1;
}
printf("%.3lf\n", check(r));
}
int main(){
int test;
scanf("%d", &test);
while(test --){
scanf("%lf%lf%lf", &H, &h, &D);
solve();
}
return 0;
}
[HDU Line belt]三分再三分
#include <bits/stdc++.h>
using namespace std;
struct Point{
double x, y;
inline void read(){scanf("%lf%lf", &x, &y);}
}A, B, C, D;
#define Sqr(x) (x)*(x)
double Len(const Point& a, const Point& b){
return sqrt(Sqr(a.x-b.x) + Sqr(a.y-b.y));
}
int P, Q, R;
double T(double a, double b){
Point X, Y;
X.x = a * (B.x - A.x) + A.x;
X.y = a * (B.y - A.y) + A.y;
Y.x = b * (C.x - D.x) + D.x;
Y.y = b * (C.y - D.y) + D.y;
return Len(A, X) / P + Len(D, Y) / Q + Len(X, Y) / R;
}
double check(double a){
double l = 0, r = 1;
while(r - l > 1e-6){
double len = (r - l) / 3.0;
double m1 = l + len, m2 = r - len;
if(T(a, m1) < T(a, m2))r = m2;
else l = m1;
}return T(a, r);
}
int main(){
int test;
scanf("%d", &test);
while(test --){
A.read(), B.read(), C.read(), D.read();
scanf("%d%d%d", &P, &Q, &R);
double l = 0, r = 1;
while(r - l > 1e-6){
double len = (r - l) / 3.0;
double m1 = l + len, m2 = r - len;
if(check(m1) < check(m2))r = m2;
else l = m1;
}
printf("%.2lf\n", check(r));
}
return 0;
}
[POJ 3301]Texas Trip
如果平行于坐标轴的正方形很好计算
如何计算歪的正方形嘞??
旋转角度嘛。一个关于旋转角度的下凸函数
然后三分角度QAQ orz神
#include <cmath>
#include <algorithm>
#include <cstdio>
#define maxn 100
using namespace std;
int n;
struct Point{
double x, y;
}a[maxn], b[maxn];
#define Sqr(x) x * x
double check(){
double lf = 1e12, rg = -1e12;
double up = rg, dw = lf;
for(int i = 1; i <= n; i ++){
lf = min(lf, a[i].x);
rg = max(rg, a[i].x);
up = max(up, a[i].y);
dw = min(dw, a[i].y);
}
return Sqr(max(rg - lf, up - dw));
}
const double pi = acos(-1.0);
double Mdf(double x){
for(int i = 1; i <= n; i ++){
a[i].x = b[i].x * cos(x) - b[i].y * sin(x);
a[i].y = b[i].x * sin(x) + b[i].y * cos(x);
}
return check();
}
void solve(){
double l = 0, r = pi;
for(int i = 1; i <= 10000; i ++){
double len = (r - l) / 3;
double m1 = l + len, m2 = r - len;
if(Mdf(m1) < Mdf(m2)) r = m2;
else l = m1;
}
printf("%.2lf\n", Mdf(l));
}
int main(){
int test;
scanf("%d", &test);
while(test --){
scanf("%d", &n);
for(int i = 1; i <= n; i ++)
scanf("%lf%lf", &b[i].x, &b[i].y);
solve();
}
return 0;
}
首先这是一个线性规划问题,有100000个变元,2个约束条件。0并不是一个初始解,所以对偶一下,100000个约束条件,2个变元。发现并不能线性规划单纯形,考虑一些半平面的交是上凸函数,所以确定y1可以找出y2的值,所以可以三分啦(然而标解是二分+凸包)
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int n, p, q;
int a[maxn], b[maxn];
double check(double y){
double ret = 0x7fffffff;
for(int i = 1; i <= n; i ++)
ret = min(ret, (1.0 - a[i] * y) / b[i]);
return q * ret + p * y;
}
int main(){
scanf("%d%d%d", &n, &p, &q);
int x = 0;
for(int i = 1; i <= n; i ++){
scanf("%d%d", &a[i], &b[i]);
if(a[i] > x) x = a[i];
}
double l = 0, r = 1.0 / x;
for(int i = 1; i <= 300; i ++){
double len = (r - l) / 3;
double m1 = l + len, m2 = r - len;
if(check(m1) < check(m2)) l = m1;
else r = m2;
}
printf("%.12lf\n", check(l));
return 0;
}
[SDOI 2013]保护出题人
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
typedef long long ll;
ll n, d;
ll a[maxn], x[maxn];
/*
每一关的独立性。
攻击力 = Max((sum[i] - sum[j-1]) / (xi + (i - j) * d))
*/
ll sum[maxn];
struct Point{
ll x, y;
Point(ll a = 0, ll b = 0):x(a), y(b){}
};
double operator * (const Point& a, const Point& b){
return (double)a.x * b.y - (double)a.y * b.x;
}
Point st[maxn];
Point operator - (const Point &a, const Point &b){
return Point(a.x - b.x, a.y - b.y);
}
int top;
int i;
double check(int p){
return (double)(sum[i] - st[p].y) / (x[i] + i * d - st[p].x) ;
}
int main(){
scanf("%lld%lld", &n, &d);
for(int j = 1; j <= n; j ++)
scanf("%lld%lld", &a[j], &x[j]);
double ans = 0;
for(i = 1; i <= n; i ++){
sum[i] = sum[i-1] + a[i];
Point now = Point(i * d, sum[i-1]);
while(top > 1 && (st[top] - st[top-1]) * (now - st[top]) <= 0)
top --;
st[++ top] = now;
int l = 1, r = top;
while(r - l >= 3){
int m1 = (l + l + r) / 3, m2 = (l + r + r) / 3;
if(check(m1) < check(m2)) l = m1;
else r = m2;
}
int mx = l;
for(int j = l + 1; j <= r; j ++)
if(check(j) > check(mx))
mx = j;
l = mx;
ans += (double)(sum[i] - st[l].y) / (x[i] + i * d - st[l].x);
}
printf("%.0lf\n", ans);
return 0;
}
/*
Input
5 2
3 3
1 1
10 8
4 8
2 3
Output
7
1≤n≤10^5,1≤d≤10^12,1≤x≤10^12,1≤a≤10^12
*/