题目链接:hdu 6070 Dirt Ratio
题意:
给你n个数,让你找一段区间[l,r],使得[l,r]中不同的数的个数size/(r-l+1)最小。
题解:
Claris官方题解:
1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 5 const int N=6e4+7; 6 int t,n,a[N],lazy[N*4],la[N]; 7 double T[N*4],eps=1e-4; 8 9 void build(double v,int l=1,int r=n,int rt=1) 10 { 11 lazy[rt]=0; 12 if(l==r){T[rt]=l*v;return;} 13 int mid=l+r>>1; 14 build(v,l,mid,rt<<1),build(v,mid+1,r,rt<<1|1); 15 T[rt]=min(T[rt<<1],T[rt<<1|1]); 16 } 17 18 void PD(int rt) 19 { 20 lazy[rt<<1]+=lazy[rt],lazy[rt<<1|1]+=lazy[rt]; 21 T[rt<<1]+=lazy[rt],T[rt<<1|1]+=lazy[rt],lazy[rt]=0; 22 } 23 24 void update(int L,int R,int v,int l=1,int r=n,int rt=1) 25 { 26 if(L<=l&&r<=R){lazy[rt]+=v,T[rt]+=v;return;} 27 int mid=l+r>>1; 28 if(lazy[rt])PD(rt); 29 if(L<=mid)update(L,R,v,l,mid,rt<<1); 30 if(R>mid)update(L,R,v,mid+1,r,rt<<1|1); 31 T[rt]=min(T[rt<<1],T[rt<<1|1]); 32 } 33 34 double ask(int L,int R,int l=1,int r=n,int rt=1) 35 { 36 if(L<=l&&r<=R)return T[rt]; 37 int mid=l+r>>1; 38 if(lazy[rt])PD(rt);double ans=1e12; 39 if(L<=mid)ans=min(ans,ask(L,R,l,mid,rt<<1)); 40 if(R>mid)ans=min(ans,ask(L,R,mid+1,r,rt<<1|1)); 41 return ans; 42 } 43 44 int check(double mid) 45 { 46 build(mid),memset(la,0,sizeof(la)); 47 F(r,1,n) 48 { 49 update(la[a[r]]+1,r,1); 50 la[a[r]]=r; 51 if(ask(1,r)<=mid*(r+1))return 1; 52 } 53 return 0; 54 } 55 56 int main(){ 57 scanf("%d",&t); 58 while(t--) 59 { 60 scanf("%d",&n); 61 F(i,1,n)scanf("%d",a+i); 62 double l=0,r=1,mid; 63 F(ic,1,15) 64 { 65 if(r-l<eps)break; 66 mid=(l+r)/2; 67 if(check(mid))r=mid;else l=mid; 68 } 69 printf("%f ",mid); 70 } 71 return 0; 72 }