题目链接

题目意思

给出n个数,求任意区间【left,right】的AC率中最小的那个值。
区间AC率=distinct【left,right】/(right-left+1)
distinct的中文意思是唯一的,特殊的,表示区间【left,right】中不同数字的个数

解题思路

我们求AC率,它无非就是0~1之间的一个数字,因此采用二分答案的方法求解。
现在假设答案为mid,则 distinct【left,right】/(right-left+1)<=mid,说明答案是小于mid的。
上边的式子可以进行变形得:

distinct【left,right】<=mid*(right-left+1)distinct【left,right】+mid*left<=mid*(right+1)

因此确定一个mid值,我们构建一棵空的线段树,每个节点的值先赋值为mid*left,其中left为当前节点的左边界,对于线段树的每个节点我们存放的是:distinct【left,right】+mid*left,对于这些节点我们维护的是节点所代表区间的最小值,因为固定右边界的时候,右侧mid*(right+1)是固定的,我们需要让左侧尽量小。

那么需要更新的就是distinct【left,right】区间中的值。我们可以通过遍历右边界,数组中的每个数都可以作为右边界,对于新加入线段树的a[i]。

pre[a[i]]记录前一次a[i]这个数字出现的位置,因此我们知道在这次遇见a[i]之前,pre[a[i]]+1~i,这些位置都没有出现过a[i]这个数字,所以在线段树中区间pre[a[i]]~i,应该加上1,就是a[i]这个数字。

更新完后,我们就可以查询【1,i】这个区间,原来我比较不理解这里,后来想明白了,1~i,这个区间求解的时候,这个区间包含许多子区间,例如【2,i】,【3,i】,【4,i】~【i,i,】。这样的话每次插入第i个数,相当于从这些区间中求了一个distinct【left,right】+mid*left 的最小值。

在循环过程中,只要有一个值小于mid*(right+1),就说明我们假设的值偏大了,循环完了也没出现这种情况
说明假设的值偏小了。

代码部分

#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
#define eps 1e-6
#define inf 0x3f3f3f3f
#define lchild left,mid,root<<1
#define rchild mid+1,right,root<<1|1const int maxn=60010;
int a[maxn];
double Min[maxn<<2];///线段树节点值
double lazy[maxn<<2];///懒惰标记数组
int pre[maxn];///pre[i]用来存放i这个数上一次出现的时候在数组中的位置
///更新当前节点
void push_up(int root)
{Min[root]=min(Min[root<<1],Min[root<<1|1]);
}
///懒惰标记下推
void push_down(int root)
{if(lazy[root]>eps){Min[root<<1]+=lazy[root];lazy[root<<1]+=lazy[root];Min[root<<1|1]+=lazy[root];lazy[root<<1|1]+=lazy[root];lazy[root]=0;}
}
///构建线段树
void build(int left,int right,int root,double temp)
{Min[root]=left*temp;lazy[root]=0;if(left==right)return;int mid=(left+right)>>1;build(lchild,temp);build(rchild,temp);push_up(root);
}
///区间更新,同时加上add
void updata(int L,int R,int add,int left,int right,int root)
{if(L<=left&&right<=R){Min[root]+=add;lazy[root]+=add;return;}push_down(root);int mid=(left+right)>>1;if(L<=mid)updata(L,R,add,lchild);if(R>mid)updata(L,R,add,rchild);push_up(root);
}
///区间查找操作
double query(int L,int R,int left,int right,int root)
{if(L<=left&&right<=R)return Min[root];push_down(root);double ans=inf*1.0;int mid=(left+right)>>1;if(L<=mid)ans=min(ans,query(L,R,lchild));if(R>mid)ans=min(ans,query(L,R,rchild));return ans;
}
///判断二分答案偏大还是偏小
bool check(int n,double temp)
{build(1,n,1,temp);memset(pre,0,sizeof(pre));for(int i=1; i<=n; i++){updata(pre[a[i]]+1,i,1,1,n,1);double minimum=query(1,i,1,n,1);pre[a[i]]=i;if(temp*(i+1)-minimum>=eps)return true;}return false;
}
int main()
{int t,n;scanf("%d",&t);while(t--){scanf("%d",&n);for(int i=1; i<=n; i++){scanf("%d",&a[i]);}double L,R,mid,ans;L=0;R=1;for(int i=0; i<30; i++){mid=(L+R)/2.0;if(check(n,mid))R=ans=mid;elseL=ans=mid;}printf("%.10lf\n",ans);}return 0;
}

HDU 6070 Dirt Ratio相关推荐

  1. HDU - 6070 Dirt Ratio (二分 + 线段树)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6070 题目大意:给定一个序列a,对于任何一个区间 [l,r],它的"Dirt Ratio&q ...

  2. HDU 6070 Dirt Ratio(线段树、二分)

    http://acm.hdu.edu.cn/showproblem.php?pid=6070 题解 首先不难看出错误率是单调的,那么我们可以直接二分答案x,某个区间的错误率=区间数的种类cnt/区间长 ...

  3. HDU 6070 Dirt Ratio

    暑假多校赛的一道题,印象深刻,今天终于补了,现在感觉也不是特别难,题意是很经典的那种问题,就是给你一个数列,问一个区间不同的个数比区间的长度的值,在这个数列里的最小值.之前搜过区间不同数的个数的查询问 ...

  4. 【二分】【线段树】hdu6070 Dirt Ratio

    size(l,r)表示区间l,r权值的种类数,让你求min{size(l,r)/(r-l+1)}(1<=l<=r<=n). last[r]表示a[r]上一次出现的位置, 就是二分验证 ...

  5. hdu 2489 Minimal Ratio Tree

    https://vjudge.net/problem/HDU-2489 题意:求一个完全图的最优比率生成树,点的个数由题给出.最优比率生成树是边的权值之和与点的权值之和的比值最小的生成树. 思路:一开 ...

  6. hdu 2489 Minimal Ratio Tree (DFS枚举+MST)

    参考链接:http://blog.csdn.net/xingyeyongheng/article/details/9373271 http://www.cnblogs.com/chenxiwenruo ...

  7. 2017 Multi-University Training Contest - Team 4:1004. Dirt Ratio

    题意:给你n个数,其中每个区间的权值就是这个区间内不同数的个数除以区间长度,求最小的权值 令size(l, r)表示区间[l, r]内不同数的个数,那么就是要求min(size(l, r)/(r-l+ ...

  8. 2019 CCSU GOLD!!!

    线段树专场 更新结点,更新区间,区间求和(平均数)+ 树链剖分 51Nod 1199 Money out of Thin Air 更新结点,区间最值,结点查找,区间求和 51Nod 1364 最大字典 ...

  9. 2019.9.17最小生成树知识点回顾

    POJ 1797 Heavy Transportation(最大生成树-Prim) 最大生成树,方法模仿最小生成树,每次选最大边进行操作,即可. HDU 5723 Abandoned country( ...

  10. 杭电OJ分类题目(4)-Graph

    原题出处:HDOJ Problem Index by Type,http://acm.hdu.edu.cn/typeclass.php 杭电OJ分类题目(4) HDU Graph Theory - U ...

最新文章

  1. 腾讯8篇AI医疗论文入选国际学术顶会,涵盖癌症图像分类、CT病灶检测等领域...
  2. selenium+chromedriver爬取淘宝美食信息保存到MongoDB
  3. 人人有奖 | 六一儿童节,大人也有礼品拿!
  4. CSS文本超出2行就隐藏并且显示省略号
  5. 杭电oj2047-2049、2051-2053、2056、2058
  6. 求10 翻译c语言,求助:谁能帮我翻译下最基础的C语言,我是新手,谢谢了!
  7. java被放弃了_为什么学Java那么容易放弃?
  8. 更改盘符实现文件服务器的特使需求
  9. Python项目:实现微信聊天机器人
  10. Java基础之深入认识hashCode和equals
  11. python比java难吗-Python 的开发效率真的比 Java高吗?
  12. 2014 android 应用开发大赛,2014年全国高校移动互联网应用开发创新大赛
  13. Python 包管理工具poetry配置国内PyPI镜像源
  14. 问卷调查设计应注意避免的六大禁忌
  15. Python安装Github下载的包,以SimpleCV为例
  16. iOS测试之移动App测试指南
  17. ignite安装与启动
  18. 2007年日历带农历表_2007年日历表,2007年农历表(阴历阳历节日对照表)
  19. 微型计算机是以微处理器为基础,在计算机中以微处理器为核心组成的微型计算机属于第几代计算机...
  20. ssh反向代理实现内网穿透;ssh+nginx实现公网云服务器代理访问内网服务器

热门文章

  1. 高端存储十面埋伏 华为全闪存系列亮剑出击
  2. ftp服务器上传文件太慢,ftp服务器上传文件速度多少
  3. java简历校园经历_简历中的校园经历怎么写
  4. 【STATA】ARIMA模型(含代码)
  5. 身上黑色素怎么去除?去黑色素方法
  6. 稀疏矩阵的三种存储方法
  7. springboot如何访问html页面,Springboot访问html页面的教程详解
  8. 使用john破解密码
  9. 出版物设计排版工具:Swift Publisher 5 for Mac
  10. 识别中文_关于开展中文语音识别和语音合成基础服务可信评估的通知