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;
}

浙公网安备 33010602011771号