http://acm.hdu.edu.cn/showproblem.php?pid=6070
题解
首先不难看出错误率是单调的,那么我们可以直接二分答案x,某个区间的错误率=区间数的种类cnt/区间长度r-l+1,变成:cnt+l*x<r*x+x;然后枚举区间区间右端点r,当前点影响的区间是le[i]+1到i,关于区间操作我们可以用线段树区间更新和区间查询最小值。
1 #define dbg(x) cout<<#x<<" = "<< (x)<< endl 2 #define IO std::ios::sync_with_stdio(0); 3 #include <bits/stdc++.h> 4 #define iter ::iterator 5 using namespace std; 6 typedef long long ll; 7 typedef pair<ll,ll>P; 8 #define pb push_back 9 #define se second 10 #define fi first 11 #define rs o<<1|1 12 #define ls o<<1 13 #define inf 0x3f3f3f3f 14 const int N=6e4+5; 15 int T,n; 16 int a[N],add[N*4]; 17 double minv[N*4],x; 18 void push(int o){ 19 minv[o]=min(minv[ls],minv[rs]); 20 } 21 void down(int o){ 22 if(add[o]){ 23 minv[ls]+=add[o]; 24 minv[rs]+=add[o]; 25 add[ls]+=add[o]; 26 add[rs]+=add[o]; 27 add[o]=0; 28 } 29 } 30 void build(int o,int l,int r){ 31 add[o]=0; 32 if(l==r){ 33 minv[o]=x*l; 34 return; 35 } 36 int m=(l+r)/2; 37 build(ls,l,m); 38 build(rs,m+1,r); 39 push(o); 40 } 41 void up(int o,int l,int r,int ql,int qr,int v){ 42 if(l>=ql&&r<=qr){ 43 add[o]+=v; 44 minv[o]+=v; 45 return; 46 } 47 down(o); 48 int m=(l+r)/2; 49 if(ql<=m)up(ls,l,m,ql,qr,v); 50 if(qr>m)up(rs,m+1,r,ql,qr,v); 51 push(o); 52 } 53 double qu(int o,int l,int r,int ql,int qr){ 54 if(l>=ql&&r<=qr){ 55 return minv[o]; 56 } 57 int m=(l+r)/2; 58 double res=1e9; 59 down(o); 60 if(ql<=m)res=min(res,qu(ls,l,m,ql,qr)); 61 if(qr>m)res=min(res,qu(rs,m+1,r,ql,qr)); 62 return res; 63 } 64 int pre[N],le[N]; 65 int check(){ 66 build(1,1,n); 67 for(int i=1;i<=n;i++){ 68 up(1,1,n,le[i]+1,i,1); 69 double res=qu(1,1,n,1,i); 70 if(res<=x*(i+1))return 1; 71 } 72 return 0; 73 } 74 int main(){ 75 scanf("%d",&T); 76 while(T--){ 77 scanf("%d",&n); 78 memset(le,0,sizeof(le)); 79 memset(pre,0,sizeof(pre)); 80 for(int i=1;i<=n;i++){ 81 scanf("%d",&a[i]); 82 le[i]=pre[a[i]]; 83 pre[a[i]]=i; 84 } 85 double l=0,r=1; 86 for(int i=1;i<=30;i++){ 87 double m=(l+r)/2; 88 x=m; 89 if(check())r=m; 90 else l=m; 91 } 92 printf("%.9lf\n",x); 93 } 94 }