HDU 6070 Dirt Ratio 线段树 + 二分
来源:互联网 发布:淘宝积分在哪里查看 编辑:程序博客网 时间:2024/05/29 00:34
传送门:HDU6070
题意:给出一段序列,找出其中一段子序列,使得子序列中不同元素个数除以子序列元素总数最大。
思路:
先贴上官方题解:
二分答案mid,检验是否存在一个区间满足r−l+1size(l,r)≤mid,也就是size(l,r)+mid×l≤mid×(r+1)。
从左往右枚举每个位置作为r,当r变化为r+1时,对size的影响是一段区间加1,线段树维护区间最小值即可。
时间复杂度O(nlognlogw)。
看官方题解大体思路能确定下来了,就是二分 + 线段树check,但是怎么在枚举右端点的时候维护这个最小值还不是很明了,其实这个线段树的用法和前几天的codeforce 834D 很相似,每次check重新建树,然后右端点每右移一次,就将该位置的数前一次出现的位置 + 1 到该位置这一段区间在线段树上更新(因为出现了新的元素),线段树每个叶子节点保存的是选当前结点当左端点产生的贡献(也就是上面红字公式的左半边)。代码:
#include<bits/stdc++.h>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;typedef pair<int,int>P;const int MAXN=100010;const double eps = 1e-8;double tree[MAXN << 2];int lazy[MAXN << 2];int a[MAXN];int last[MAXN], pre[MAXN];void push_up(int rt){tree[rt] = min(tree[rt << 1], tree[rt << 1 | 1]);}void push_down(int rt){if(!lazy[rt]) return ;lazy[rt << 1] += lazy[rt];lazy[rt << 1 | 1] += lazy[rt];tree[rt << 1] += lazy[rt];tree[rt << 1 | 1] += lazy[rt];lazy[rt] = 0;}void build(double c, int l, int r, int rt){tree[rt] = lazy[rt] = 0;if(l == r){tree[rt] = c * l;return ;}int mid = (l + r) >> 1;build(c, lson);build(c, rson);push_up(rt);}void update(int L, int R, int l, int r, int rt){if(L <= l && r <= R){lazy[rt]++;tree[rt] += 1;return ;}push_down(rt);int mid = (l + r) >> 1;if(L <= mid)update(L, R, lson);if(R > mid)update(L, R, rson);push_up(rt);}double query(int L, int R, int l, int r, int rt){if(L <= l && r <= R){return tree[rt];}push_down(rt);int mid = (l + r) >> 1;double ans = inf;if(L <= mid)ans = min(ans, query(L, R, lson));if(R > mid)ans = min(ans, query(L, R, rson));return ans;}bool check(double mid, int n){build(mid, 1, n, 1);double tmp;for(int i = 1; i <= n; i++){update(pre[i] + 1, i, 1, n, 1);tmp = query(1, i, 1, n, 1);if(tmp < mid * (i + 1) + eps) return 1;}return 0;}int main(){int T, n;cin >> T;while(T--){cin >> n;memset(last, 0, sizeof(last));for(int i = 1; i <= n; i++){scanf("%d", a + i);pre[i] = last[a[i]];last[a[i]] = i;}double l = 0, r = 1, mid;for(int i = 0; i < 20; i++){mid = (l + r) / 2;if(check(mid, n))r = mid;elsel = mid;}printf("%.5lf\n", mid);} return 0;}
阅读全文
0 0
- HDU 6070 Dirt Ratio 线段树 二分
- HDU 6070 Dirt Ratio [二分+线段树]
- hdu 6070 Dirt Ratio 二分,线段树
- hdu 6070 Dirt Ratio(线段树+二分)
- hdu 6070 Dirt Ratio二分 线段树
- HDU 6070 Dirt Ratio 线段树 + 二分
- 【HDU 6070 Dirt Ratio】 二分 & 线段树
- HDU 6070 Dirt Ratio 二分+线段树
- HDU 6070 Dirt Ratio(二分+线段树)
- HDU-6070 Dirt Ratio(二分+线段树+分数规划)
- hdu 6070 Dirt Ratio(二分+线段树维护区间最小值)
- HDU 6070 Dirt Ratio(二分+线段树)
- hdu 6070 Dirt Ratio(线段树+二分答案)
- HDU 6070 Dirt Ratio (线段树+二分)
- HDU 6070 Dirt Ratio(二分+线段树)
- HDU 6070 Dirt Ratio 线段树
- HDU 6070 Dirt Ratio 分数规划 二分 线段树维护区间最值
- HDU 6070 Dirt Ratio (二分+线段树, 2017 Multi-Univ Training Contest 4)
- Git中fetch和pull命令的区别
- sudo 命令能为你做些什么
- 求解最大连续子数组问题
- (2)window方法:confirm、setTimeout、setInterval、clearInterval、moveBy和moveTo、open和close
- CodeForces
- HDU 6070 Dirt Ratio 线段树 + 二分
- 201412-2 Z字形扫描
- 问题 E: YK的书架
- Agri-Net (最小生成树)
- 异常检测之正态分布
- EL表达式和JSTL标签库
- 一个文本跑马灯的“学”案
- 观察者模式
- InnoDB关键特性之自适应hash索引