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

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 }

猜你喜欢

转载自www.cnblogs.com/ccsu-kid/p/10785763.html