HDU6070 Dirt Ratio (01规划+线段树)

来源:互联网 发布:asp.net 的优势php 编辑:程序博客网 时间:2024/06/06 02:21

HDU6070 Dirt Ratio (01规划+线段树)

题目解释

求一个区间内,不同数个数与区间长度的比的最小值

题目分析

Code10min,Debug30min+。
对于求区间比率问题,一般情况下为01规划。

代码

#include <stdio.h>#include <cstring>#include <algorithm>using namespace std;const int maxn = 60010;int a[maxn], last[maxn], ql, qr;double valv[4 * maxn], addv[4 * maxn], qv;void Maintain(int o, int l, int r){    valv[o] = (r - l > 1 ? min(valv[2 * o], valv[2 * o + 1]) : 0) + addv[o];}void Add(int o, int l, int r){    if(ql <= l && r <= qr) addv[o] += qv;    else{        int mid = (l + r) / 2;        if(ql < mid) Add(2 * o, l, mid);        if(mid < qr) Add(2 * o + 1, mid, r);    }    Maintain(o, l, r);}double Query(int o, int l, int r){    if(ql <= l && r <= qr) return valv[o];    else{        int mid = (l + r) / 2; double rnt = 1e9;        if(ql < mid) rnt = min(rnt, Query(2 * o, l, mid));        if(mid < qr) rnt = min(rnt, Query(2 * o + 1, mid, r));        return rnt + addv[o];    }}bool Solve(double mid, int n){    memset(last, 0, sizeof(last));    memset(valv, 0, sizeof(valv));    memset(addv, 0, sizeof(addv));    for(int i = 1; i <= n; i++){        ql = i; qr = i + 1; qv = i * mid;        Add(1, 1, n + 1);        ql = last[a[i]] + 1; qr = i + 1; qv = 1;        if(ql < qr) Add(1, 1, n + 1);        last[a[i]] = i;        ql = 1; qr = i + 1;         if(Query(1, 1, n + 1) <= (i + 1) * mid) return true;    }    return false;}int main(){    int T; scanf("%d", &T);    while(T--){        int n; scanf("%d", &n);        for(int i = 1; i <= n; i++)            scanf("%d", &a[i]);        double l = 0, r = 1;        while(r - l > 1e-6){            double mid = (l + r) / 2;            if(Solve(mid, n)) r = mid;            else l = mid;        }        printf("%lf\n", r);    }    return 0;}

反思

喵喵喵

原创粉丝点击