hdu-6070(二分+线段树)
2017-08-04 10:34
246 查看
---------题目链接,戳这里------------
题目意思:
题目一通描述,弄得我完全懵逼。幸好讨论区,有题目意思。
题目意思为:定义f(l,r) 为区间 [l,r] 的不同元素个数/区间长度。求最小的 f(l,r) 定义域:\(0 < l \leqslant r \leqslant n\)。题目意思,翻译转一下就是这么简单。
思路:
思路就是,官方题解给出的,二分+线段树;我们二分答案,mid。需要判断mid是否满足,假设我们定义 \(size\left ( l,r \right )\)为区间 [l,r] 的不同元素个数。那么就需要mid满足:\(\frac{size\left ( l,r \right )}{r-l+1}\leq mid\),按照题解进行变形式子可以得到:\(size \left ( l,r \right )+ mid \times l \leq mid \times \left ( r+1 \right )\),我们可以对r进行从左到右的枚举。在每一次枚举中r就是一个常数。我们可以用线段树维护区间最小值,维护 \(size \left ( l,r \right )+ mid \times l\) ,每次r+1,需要更新r,r这个区间,区间加mid×r。还有需要给r区间到之前出现a[r]位置的右边这个区间的size都会加1。所以两次更新,每次我们需要查询区间 [1,r] 的区间最小值。先写一个区间维护最小值的插线问线的线段树。进行二分 。over;二分的时候,如果满足条件说明mid还不是最小的所以把上限\(r = mid\),否则下限\(l = mid\);
代码比较搓。还好能够AC (-.-)
#include <cstdio> #include <cstring> #include <cctype> #include <cmath> #include <set> #include <map> #include <list> #include <queue> #include <deque> #include <stack> #include <string> #include <vector> #include <iostream> #include <algorithm> #include <stdlib.h> #include <time.h> using namespace std; typedef long long LL; const LL INF = 2e9 + 1e8; const double eps = 0.0000000001; void fre() { freopen("test.in", "r", stdin); freopen("test.out", "w", stdout); } #define MSET(a, b) memset(a, b, sizeof(a)) const int MOD = 1e9 + 7; const int maxn = 1e6 + 100; int a[maxn], pre[maxn], pos[maxn]; struct nyist { double tree[maxn], lazy[maxn]; void init() { MSET(tree, 0); MSET(lazy, 0); } void pushdown(int i) { if (lazy[i] > eps) { tree[i << 1] += lazy[i], tree[i << 1 | 1] += lazy[i]; lazy[i << 1] += lazy[i], lazy[i << 1 | 1] += lazy[i]; lazy[i] = 0; } } void update(int i, int l, int r, int L, int R, double k) { if (L == l && R == r) { tree[i] += k; lazy[i] += k; return; } pushdown(i); int mid = (l + r) >> 1; if (R <= mid) update(i << 1, l, mid, L, R, k); else if (L > mid) update(i << 1 | 1, mid + 1, r, L, R, k); else update(i << 1, l, mid, L, mid, k), update(i << 1 | 1, mid + 1, r, mid + 1, R, k); tree[i] = min(tree[i << 1], tree[i << 1 | 1]); } double query(int i, int l, int r, int L, int R) { if (L == l && r == R) return tree[i]; pushdown(i); int mid=(l+r)>>1; if(R<=mid) return query(i<<1,l,mid,L,R); else if(L>mid) return query(i<<1|1,mid+1,r,L,R); else return min(query(i<<1,l,mid,L,mid),query(i<<1|1,mid+1,r,mid+1,R)); } } ac; int main() { int ncase; scanf("%d", &ncase); while (ncase--) { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); MSET(pos,0); for (int i = 1; i <= n; i++) { pre[i]=pos[a[i]]; pos[a[i]]=i; } double l = 0, r = 1.0,res; while (fabs(l-r)>eps) { ac.init(); double mid = (l + r) / 2; bool flag = false; for (int i = 1; i <= n; i++) { ac.update(1, 1, n, i, i, mid *i); ac.update(1,1,n,pre[i]+1,i,1.0); double ans=ac.query(1,1,n,1,i); if(ans<=mid*(i+1)) { flag=true; break; } } if(flag) r=mid,res=mid; else l=mid; } printf("%lf\n",res); } return 0; }
相关文章推荐
- HDU 6070 Dirt Ratio [二分+线段树]
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树维护区间最小值)
- HDU 6070 二分查找 + 线段树 + 枚举
- 【HDU 6070 Dirt Ratio】 二分 & 线段树
- HDU 6070 Dirt Ratio(二分+线段树)
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio二分 线段树
- HDU 6070 Dirt Ratio(二分+线段树 17多校第四场)
- HDU 6070 Dirt Ratio 分数规划 二分 线段树维护区间最值
- HDU - 6070 - Dirt Ratio(二分+线段树)
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- D - Dirt Ratio HDU - 6070详解 (二分+线段树区间修改+思维)
- hdu 6070 Dirt Ratio 二分,线段树
- (2017多校4)1004/hdu-6070 Dirt Ratio(二分 + 线段树)
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- 2017 Multi-University Training Contest - Team 4 HDU 6070 Dirt Ratio (二分+ 线段树)
- HDU 6070 Dirt Ratio(二分+线段树)
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )