1. 程式人生 > >GYM-100520 B. Bayes' Law

GYM-100520 B. Bayes' Law

題解:區間[L,R]得出的答案我們知道,它最多有一個端點的線段會被截斷。故二分的時候固定一個線段的端點就好了。然後列舉最右端的那條線段是否被分隔開。 然後固定右端點,分割左端點的線段。

#include<bits/stdc++.h>
#define fuck(x) cout<<'['<<#x<<' '<<x<<']'<<endl
using namespace std;
const double eps = 1e-8;
typedef long long ll;
const int MX = 2e5+7;
double cnt[MX],sum[MX],x[MX],y[MX];
int n,tail;
double L,R,ans;
int dcmp(double a)
{
    if(fabs(a) < eps) return 0;
    return a < 0? -1 : 1;
}

double check(int id, double mid)
{
    int k = lower_bound(cnt,cnt+tail,mid) - cnt;
    k = min(tail-1,k);
    double ret = sum[k] - sum[id];
    if(k&1) ret -= max(0.0, cnt[k]-mid); //線段是1-0,3-2,5-4這樣的,所以必須是奇數才能減
    return ret;
}

void update(int id, double mid, bool rev)
{
    double l,r;
    if(rev){
        r = x[n] - cnt[id];
        l = x[n] - mid;
    }
    else{
        l = cnt[id];
        r = mid;
    }

    if(dcmp(r-l-ans) <= 0){
        ans = r-l;
        L = l;
        R = r;
    }
}

void work(bool rev,double A)
{
    for(int i = 0; i < tail; i += 2){
        double l = cnt[i], r = x[n]+1;
        for(int j = 1; j <= 60; j++){
            double mid = (l+r)*0.5;
            if(dcmp(check(i,mid)-A ) >= 0) r = mid;
            else l = mid;
        }
        if(l > x[n]+0.1) break;
        update(i,l,rev);
    }
}

int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#else
    freopen("bayes.in", "r", stdin);
    freopen("bayes.out", "w", stdout);
#endif // LOCAL
    double a,b,A;
    while(~scanf("%d",&n)){
        if(n == 0) break;

        tail = 0;
        scanf("%lf%lf%lf",&a,&b,&A);
        for(int i = 0; i <= n; i++){
            scanf("%lf%lf",&x[i],&y[i]);
        }
        for(int i = 1; i <= n; i++){
            double dx = x[i] - x[i-1], dy = y[i] - y[i-1];
            if(dcmp(dy) == 0 && a <= y[i] && y[i] <= b){
                cnt[tail++] = x[i-1];
                cnt[tail++] = x[i];
            }
            else{
                double t = dy/dx;
                double xl = x[i-1] + (t < 0? (b-y[i-1])/t : (a-y[i-1])/t);
                double xr = x[i] + (t < 0? (a-y[i])/t : (b-y[i])/t );
                xl = max(xl,x[i-1]);
                xr = min(xr,x[i]);
                if(xl > xr) continue;
                cnt[tail++] = xl;
                cnt[tail++] = xr;
            }
        }

        double len = 0;
        for(int i = 1; i < tail; i+=2){
            len += cnt[i] - cnt[i-1];
        }
        A *= len;
        ans = x[n]; L = 0, R = 0;

        for(int i = 1; i < tail; i++){
            if(i&1) sum[i] = sum[i-1] + cnt[i] - cnt[i-1];
            else sum[i] = sum[i-1];
        }
        work(0,A);

        for(int i = 0; i < tail; i++)
            cnt[i] = x[n] - cnt[i];
        reverse(cnt,cnt+tail);
        for(int i = 1; i < tail; i++){
            if(i&1) sum[i] = sum[i-1] + cnt[i] - cnt[i-1];
            else sum[i] = sum[i-1];
        }
        work(1,A);
        printf("%.12f %.12f\n",L,R);
    }
    return 0;
}