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

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;
}

反思

喵喵喵

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值