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;
}
反思
喵喵喵