HDU 6070 Dirt Ratio
Posted MeowMeowMeow
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6070 Dirt Ratio相关的知识,希望对你有一定的参考价值。
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070
题意:给出一个数列,定义len为某一区间长度,定义size为区间数字种类数,求所有区间最小的size/len;
思路:线段树+二分答案
对于所有区间的l,r而言,所求为size(l,r)/(r-l+1)<=mid(二分到当前的答案),可以化为size(l,r)+mid*l<=(r+1)*mid;
然后就是线段树的维护,我们对线段树的叶子定义为所在点(即L)到当前枚举的R之间这个区间的size(l,r)+mid*l,线段树
就维护每个区间最小的size(l,r)+mid*l,就好了;又看得出来对于以上式子当其他值不变只是变mid时,随着mid增加右边比
左边增加的多(r+1>l),而我们要找最小的mid,所以只要满足以上,那么就找更小的mid来试就好;精度的话到1e-5就可以过了;
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define L l,m,u<<1 #define R m+1,r,u<<1|1 typedef long long LL; const int N=6e4+10; const double esp=1e-5; double add[N<<2],Min[N<<2]; int last[N],a[N],n; void pushUp(int u) { Min[u]=min(Min[u<<1],Min[u<<1|1]); } void pushDown(int u) { if(add[u]) { add[u<<1]+=add[u]; add[u<<1|1]+=add[u]; Min[u<<1]+=add[u]; Min[u<<1|1]+=add[u]; add[u]=0; } } void build(int l,int r,int u,double v) { add[u]=0; if(l==r) { Min[u]=l*v; return; } int m=(l+r)>>1; build(L,v); build(R,v); pushUp(u); } void update(int l1,int r1,int c,int l,int r,int u) { if(l1<=l && r<=r1) { add[u]+=c; Min[u]+=c; return; } pushDown(u); int m=(r+l)>>1; if(l1<=m) update(l1,r1,c,L); if(m<r1) update(l1,r1,c,R); pushUp(u); } double query(int l1,int r1,int l,int r,int u) { if(l1<=l && r<=r1) { return Min[u]; } pushDown(u); int m=(l+r)>>1; double ret=1e5; if(l1<=m) ret=min(ret,query(l1,r1,L)); if(m<r1) ret=min(ret,query(l1,r1,R)); return ret; } bool check(double m) { build(1,n,1,m); memset(last,0,sizeof(last)); for(int i=1;i<=n;i++) { update(last[a[i]]+1,i,1,1,n,1); last[a[i]]=i; if(query(1,i,1,n,1)<=m*(i+1))return true; } return false; } int main() { // freopen("input.txt","r",stdin); int T; for(scanf("%d",&T);T;T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); double l=0.0,r=1.0,m,ans; while(r-l>esp) { m=(l+r)/2; if(check(m))r=(ans=m); else l=m; } printf("%.9lf\n",ans); } return 0; }
以上是关于HDU 6070 Dirt Ratio的主要内容,如果未能解决你的问题,请参考以下文章