Hdu 6070 Dirt Ratio【分数规划+二分+线段树】好题~好题~
2017-08-05 15:15
543 查看
Dirt Ratio
Time Limit: 18000/9000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)Total Submission(s): 1515 Accepted Submission(s): 698
Special Judge
Problem Description
In ACM/ICPC contest, the ''Dirt Ratio'' of a team is calculated in the following way. First let's ignore all the problems the team didn't pass, assume the team passed Xproblems
during the contest, and submitted Y times
for these problems, then the ''Dirt Ratio'' is measured as XY.
If the ''Dirt Ratio'' of a team is too low, the team tends to cause more penalty, which is not a good performance.
![](http://acm.hdu.edu.cn/data/images/C762-1004-1.jpg)
Picture from MyICPC
Little Q is a coach, he is now staring at the submission list of a team. You can assume all the problems occurred in the list was solved by the team during the contest. Little Q calculated the team's low ''Dirt Ratio'', felt very angry. He wants to have a talk
with them. To make the problem more serious, he wants to choose a continuous subsequence of the list, and then calculate the ''Dirt Ratio'' just based on that subsequence.
Please write a program to find such subsequence having the lowest ''Dirt Ratio''.
Input
The first line of the input contains an integer T(1≤T≤15),
denoting the number of test cases.
In each test case, there is an integer n(1≤n≤60000) in
the first line, denoting the length of the submission list.
In the next line, there are n positive
integers a1,a2,...,an(1≤ai≤n),
denoting the problem ID of each submission.
Output
For each test case, print a single line containing a floating number, denoting the lowest ''Dirt Ratio''. The answer must be printed with an absolute error not greater than 10−4.
Sample Input
1
5
1 2 1 2 3
题目大意:
让你找到一个区间:【L,R】,使得其中的数字的种类数/区间长度最小。
问这个比例最小是多少。
思路:
考虑分数规划:
①我们希望Val【L,R】/(R-L+1)最小。这里Val【L,R】表示区间中数字的种类数。
②我们不妨设定F(X)=Val【L,R】-X*(R-L+1);
③那么如果有F(X)<=0,那么一定有Val【L,R】/(R-L+1)<=X;
④所以我们这个最小的值可以通过二分来求出来。
那么我们如何check呢?
我们再转化一下不等式变成:Val【L,R】+mid*L<=(R+1)*mid.(这里X==mid);
那么我们O(n)枚举R,之前我们可以利用线段树来维护mid*L+Val【L,R】的最小值,那么如果查询Query(1,i-1)能够<=(R+1)*mid的话,就说明可以继续向下二分。
否则向上。
我们线段树更新mid*L很简单,一路update(i,i,mid*i)即可,那么Val【L,R】怎样处理呢?其实也不难,我们维护一个数组last【i】,表示数字i出现的最后的位子,那么对于当前数i,其影响的区间Val的值的范围就是从【last【a【i】】+1,i】,那么再update一下(last【a【i】】+1,i,1)即可。
尽量去for二分。
Ac代码:
#include<stdio.h> #include<iostream> #include<string.h> using namespace std; #define lson l,m,rt*2 #define rson m+1,r,rt*2+1 double tree[350050*8]; double flag[350050*8]; int last[350050]; int a[350050]; void build(int l,int r,int rt){ flag[rt]=0; if(l==r) { tree[rt]=0; flag[rt]=0; return; } int m=(l+r)>>1; build(lson); build(rson); } void pushdown(int l,int r,int rt)//向下维护树内数据 { if(flag[rt])//如果贪婪标记不是0(说明需要向下进行覆盖区间(或点)的值) { int m=(l+r)/2; flag[rt*2]+=flag[rt]; flag[rt*2+1]+=flag[rt]; tree[rt*2]+=flag[rt];//千万理解如何覆盖的区间值(对应线段树的图片理解(m-l)+1)是什么意识. tree[rt*2+1]+=flag[rt]; flag[rt]=0; } } void pushup(int rt) { tree[rt]=max(tree[rt<<1],tree[rt<<1|1]); } double Query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R) { return tree[rt]; } else { pushdown(l,r,rt); int m=(l+r)>>1; double ans=-10000000000000; if(L<=m) { ans=max(ans,Query(L,R,lson)); } if(m<R) { ans=max(ans,Query(L,R,rson)); } pushup(rt); return ans; } } void update(int L,int R,double c,int l,int r,int rt) { if(L<=l&&r<=R)//覆盖的是区间~ { tree[rt]+=c;//覆盖当前点的值 flag[rt]+=c;//同时懒惰标记~! return ; } pushdown(l,r,rt); int m=(l+r)/2; if(L<=m) { update(L,R,c,lson); } if(m<R) { update(L,R,c,rson); } pushup(rt); } int Slove(int n,double mid) { build(1,n,1); for(int i=1;i<=n;i++)last[a[i]]=0; for(int i=1;i<=n;i++) { update(i,i,-mid*i,1,n,1); update(last[a[i]]+1,i,-1,1,n,1); last[a[i]]=i; if(i==1)continue; double Q=-Query(1,i-1,1,n,1); if(Q<=(i+1)*mid)return 1; } return 0; } 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; double r=1; double ans; for(int i=0;i<20;i++) { double mid=(l+r)/2; if(Slove(n,mid)==1) { ans=mid; r=mid; } else l=mid; } printf("%.10f\n",ans); } }
相关文章推荐
- 2017多校四 1004题 hdu 6070 Dirt Ratio 二分 + 线段树 + 分数规划
- HDU 6070 Dirt Ratio 分数规划 二分 线段树维护区间最值
- HDU 6070 Dirt Ratio【分数规划】【线段树】
- HDU-6070 Dirt Ratio(二分+线段树+分数规划)
- HDU 6070 Dirt Ratio(分数规划+线段树)
- 2017多校第4场 HDU 6070 Dirt Ratio 分数规划,线段树
- HDU 6070 Dirt Ratio [二分+线段树]
- HDU 6070 Dirt Ratio (二分+线段树, 2017 Multi-Univ Training Contest 4)
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- HDU 6070 Dirt Ratio(二分+线段树)
- hdu 6070 Dirt Ratio(二分+线段树)(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 二分,线段树
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(二分+线段树)(2017 Multi-University Training Contest - Team 4 )
- hdu 6070 Dirt Ratio(分数规划)