hdu 6070 Dirt Ratio

  OvO http://acm.hdu.edu.cn/showproblem.php?pid=6070

  (2017 Multi-University Training Contest - Team 4 - 1004)

  二分答案

  check时,要满足distinct(l,r)/(r-l+1)<val ,将这个不等式转化为distinct(l,r)+val*l<val*(r+1)

  check的时候,从左到右枚举右端点r,用线段树维护查询从1到r中选一个l,distinct(l,r)+val*l的最小值

  lst数组的作用:lst[i]表示枚举右端点时上一个值为i的点出现的位置

  这样的话,线段树的更新就是当枚举到右端点为i的时候,lst[s[i]]+1到i的值全部加1

  查询就是查询1到i中的最小值

  (思路来源 标程之类的东西)

  

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>

using namespace std;

const int M=6e4+55;

int n;
int s[M],lst[M];
double tree[M*3],tag[M*3];

void build(int rt,int li,int ri,double val)
{
	tag[rt]=0;
	if(li==ri)
	{
		tree[rt]=val*li;
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	build(lc,li,mid,val);
	build(rc,mid+1,ri,val);
	tree[rt]=min(tree[lc],tree[rc]);
}

void pushdown(int rt,int li,int ri)
{
	if(li==ri)
	{
		tag[rt]=0;
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	tree[lc]+=tag[rt];
	tree[rc]+=tag[rt];
	tag[lc]+=tag[rt];
	tag[rc]+=tag[rt];
	tag[rt]=0;
}

void update(int rt,int li,int ri,int lq,int rq,double val)	//add
{
	if(lq<=li && ri<=rq)
	{
		tag[rt]+=val;
		tree[rt]+=val;
		return ;
	}
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	if(tag[rt])
		pushdown(rt,li,ri);
	if(mid>=lq)
		update(lc,li,mid,lq,rq,val);
	if(mid+1<=rq)
		update(rc,mid+1,ri,lq,rq,val);
	tree[rt]=min(tree[lc],tree[rc]);
}

double query(int rt,int li,int ri,int lq,int rq)	//get min
{
	double ret=1e9+7;
	if(lq<=li && ri<=rq)
		return tree[rt];
	int mid=(li+ri)>>1,lc=(rt<<1),rc=(rt<<1)+1;
	if(tag[rt])
		pushdown(rt,li,ri);
	if(mid>=lq)
		ret=min(ret,query(lc,li,mid,lq,rq));
	if(mid+1<=rq)
		ret=min(ret,query(rc,mid+1,ri,lq,rq));
	return ret;
}

bool check(double val)
{
	int i,j;
	double tmp;
	build(1,1,n,val);
	memset(lst,0,sizeof(lst));
	for(i=1;i<=n;i++)
	{
		update(1,1,n,lst[s[i]]+1,i,1);
		tmp=query(1,1,n,1,i);	//tmp=distinct(l,r)+val*l  
		if(tmp<val*(i+1))	//distinct(l,r)+val*l<val*(r+1) => distinct(l,r)/(r-l+1)<val 
			return true;
		lst[s[i]]=i;
	}
	return false;
}

void solve()
{
	double li=0,ri=1,mid;
	int i,j,cnt=20;
	while(cnt--)
	{
		mid=(li+ri)/2;
		if(check(mid))
			ri=mid;
		else
			li=mid;
	}
	printf("%.10lf\n",ri);
}

int main()
{
	int i,j;
	int cas;
	cin>>cas;
	while(cas--)
	{
		scanf("%d",&n);
		for(i=1;i<=n;i++)
			scanf("%d",&s[i]);
		solve();
	}
	return 0;
}

  

posted @ 2017-08-03 23:57  太阳星人FxxL  阅读(232)  评论(0编辑  收藏  举报