hdu6070

hdu6070

题意

给出 (n) 个数, (frac{x}{y}) 表示某个区间不同数的个数除以区间的长度,求 (frac{x}{y}) 最小值。

分析

(size(l, r)) 表示 ([l, r]) 这个区间内不同数的个数,那么求得就是 (frac{size(l, r)}{r - l + 1}) 的最小值。
二分答案 (mid) ,式子转化成 (size(l, r) + mid imes l leq mid imes (r + 1))
枚举右端点 (r),线段树存的是从 (l) 到 当前枚举到的 (r)(size(l, r) + mid imes l) ,如果存在最小值满足小于等于 (mid imes (r + 1)) ,说明这个 (mid) 可以取到,更新 (mid)

新姿势:线段树内每个点的信息是动态的,和枚举到的 (r) 有关,通过区间更新就可以很方便的计算 (size(l, r)) 的值。

(last[a[i]]) 表示 (a[i]) 这个数上一次出现的位置,那么每次我们只需要区间更新 ([last[a[i]] + 1, i]) 就好了。

code

#include<bits/stdc++.h>
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
const int MAXN = 6e4 + 10;
int a[MAXN];
int last[MAXN];
double s[MAXN << 2];
double lazy[MAXN << 2];
void pushDown(int rt) {
    if(lazy[rt] > 0) {
        s[rt << 1] += lazy[rt];
        s[rt << 1 | 1] += lazy[rt];
        lazy[rt << 1] += lazy[rt];
        lazy[rt << 1 | 1] += lazy[rt];
        lazy[rt] = 0;
    }
}
void pushUp(int rt) {
    s[rt] = min(s[rt << 1], s[rt << 1 | 1]);
}
void update(int L, int R, double c, int l, int r, int rt) {
    if(L <= l && r <= R) {
        lazy[rt] += c;
        s[rt] += c;
        return;
    }
    int m = (l + r) / 2;
    pushDown(rt);
    if(L <= m) update(L, R, c, lson);
    if(R > m) update(L, R, c, rson);
    pushUp(rt);
}
double query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return s[rt];
    }
    int m = (l + r) / 2;
    pushDown(rt);
    double res = 1e12;
    if(L <= m) res = query(L, R, lson);
    if(R > m) res = min(res, query(L, R, rson));
    pushUp(rt);
    return res;
}
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.0, mid;
        while(r - l > 1e-5) {
            mid = (l + r) / 2.0;
            memset(s, 0, sizeof s);
            memset(lazy, 0, sizeof lazy);
            memset(last, 0, sizeof last);
            int flg = 0;
            for(int i = 1; i <= n; i++) {
                update(last[a[i]] + 1, i, 1, 1, n, 1);
                update(i, i, mid * i, 1, n, 1);
                if(query(1, i, 1, n, 1) <= mid * (i + 1)) {
                    flg = 1;
                    break;
                }
                last[a[i]] = i;
            }
            if(flg) r = mid;
            else l = mid;
        }
        printf("%.6f
", mid);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/7291765.html