HDU 6070 Dirt Ratio (二分+线段树, 2017 Multi-Univ Training Contest 4)

来源:互联网 发布:javascript表单事件 编辑:程序博客网 时间:2024/06/07 17:57

Problem

N 长区间每个数为 ai,任取一段区间,定义 X 表示所取区间不相同数个数,Y 表示所取区间长度,求最小 XY

Limit

1n60000

1ain

Idea

感觉比赛时候各种乱来。挂机 4 小时想不出这题的正解…

对答案进行二分枚举(:cry: 很显然有二分性,我竟然一开始就否定了)。对每次二分的答案 ratio 判断是否存在一个 XYratio

具体参见 官方题解 。

Code

#include<bits/stdc++.h>using namespace std;const int N = 60000 + 10;const double inf = 1e9;int T, n, a[N], vis[N], pre[N];double val[N];// Segment Tree #define lson l , m , rt << 1  #define rson m + 1 , r , rt << 1 | 1 const int MAXN = 60000 + 10;double add[MAXN<<2], mn[MAXN<<2];void PushUp(int rt) {   mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);   }void PushDown(int rt, int m) {    if(add[rt]) {        add[rt<<1] += add[rt];        add[rt<<1|1] += add[rt];        mn[rt<<1] += add[rt];        mn[rt<<1|1] += add[rt];        add[rt] = 0;    }}void build(int l, int r, int rt) {    add[rt] = 0;    if(l == r) {        mn[rt] = val[l];        return;    }    int m = (l+r)>>1;    build(lson);    build(rson);    PushUp(rt);}void update(int L, int R, double w, int l, int r, int rt) {    if(L>R) return;    if(L <= l && r <= R) {        add[rt] += w;        mn[rt] += w;        return;    }    PushDown(rt, r-l+1);    int m = (l+r) >> 1;    if(L <= m)  update(L, R, w, lson);    if(m < R)   update(L, R, w, rson);    PushUp(rt);}double query(int L, int R, int l, int r, int rt) {    if(L <= l && r <= R)    return mn[rt];    PushDown(rt, r-l+1);    int m = (l+r) >> 1;    double ret = inf;    if(L <= m)  ret = min(ret, query(L, R, lson));    if(m < R)   ret = min(ret, query(L, R, rson));    return ret;}bool jug(double ratio) {    for(int i=1;i<=n;i++)        val[i] = (i-1) * ratio;    build(1, n, 1);    for(int i=1;i<=n;i++)    {        update(pre[i]+1, i, 1, 1, n, 1);        double mnVal = query(1, i, 1, n, 1);        if(mnVal <= ratio * i)  return true;    }    return false;}   double solve(){    double l = 0.0, r = 1.0, mid, ans = 1.0;    for(int i=0;i<20;i++)    {        mid = (l+r) / 2;        if(jug(mid))    r = mid,    ans = mid;        else    l = mid;    }    return ans;}int main(){    scanf("%d", &T);    while(T-- && scanf("%d", &n)!=EOF)    {        memset(vis, 0, sizeof(vis));        for(int i=1;i<=n;i++)        {            scanf("%d", &a[i]);            pre[i] = vis[ a[i] ];            vis[a[i]] = i;        }        printf("%.8lf\n", solve());    }}
阅读全文
0 0
原创粉丝点击