第四场 hdu 6070 Dirt Ratio (线段树+二分)

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

 

题目大意:给出的序列上的数代表颜色,求子序列中不同数字的个数X与子序列长度Y中,X/Y的最小值

 

解题思路:思路和官方给的想法一样

值得注意的是线段树的节点中储存的是 size(l,r)+mid×l ,在建树时 mid×l 作为树节点的初始值,然后不断更新当前颜色对于 前一个相同颜色的位置+1 到 当前位置 的节点值+1,然后询问 1 到 当前位置的最小值 是否小于mid*(i+1)。

虽然最后要打印小数点后九位但是精度只要达到小数点后五位就可以了。

 

AC代码:4056MS

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 const int maxn=60100;
 5 const double eps=1e-5;
 6 int a[maxn],flag[maxn];
 7 double val[maxn<<2],lazy[maxn<<2];
 8 int t,n;
 9 void push_up(int k)
10 {
11     val[k]=min(val[k*2],val[k*2+1]);
12 }
13 void push_down(int k)
14 {
15     if(lazy[k])
16     {
17         lazy[k*2]+=lazy[k];
18         lazy[k*2+1]+=lazy[k];
19         val[k*2]+=lazy[k];
20         val[k*2+1]+=lazy[k];
21         lazy[k]=0;
22     }
23 }
24 void build(double mid,int l,int r,int k)
25 {
26     lazy[k]=0;
27     if(l==r)
28     {
29         val[k]=l*mid;
30         return ;
31     }
32     int midd=(l+r)/2;
33     build(mid,l,midd,k*2);
34     build(mid,midd+1,r,k*2+1);
35     push_up(k);
36 }
37 void init(int L,int R,int l,int r,int k)
38 {
39     if(L<=l&&r<=R)
40     {
41         val[k]=val[k]+1;
42         lazy[k]+=1;
43         return ;
44     }
45     push_down(k);
46     int mid=(l+r)/2;
47     if(L<=mid) init(L,R,l,mid,k*2);
48     if(R>mid) init(L,R,mid+1,r,k*2+1);
49     push_up(k);
50 }
51 double query(int L,int R,int l,int r,int k)
52 {
53     if(L<=l&&r<=R)
54     {
55         return val[k];
56     }
57     push_down(k);
58     int mid=(l+r)/2;
59     double ans=1e5;
60     if(L<=mid) ans=query(L,R,l,mid,k*2);
61     if(R>mid) ans=min(ans,query(L,R,mid+1,r,k*2+1));
62     push_up(k);
63     return ans;
64 }
65 bool solve(double mid)
66 {
67     memset(flag,0,sizeof(flag));
68     build(mid,1,n,1);
69     for(int i=1;i<=n;i++)
70     {
71         init(flag[a[i]]+1,i,1,n,1);
72         flag[a[i]]=i;
73         if(query(1,i,1,n,1)<=mid*(i+1)) return true;
74     }
75     return false;
76 }
77 int main()
78 {
79 
80     scanf("%d",&t);
81     //freopen("data.txt","w",stdout);
82     while(t--)
83     {
84         scanf("%d",&n);
85         for(int i=1;i<=n;i++)
86         scanf("%d",&a[i]);
87         double l=0,r=1,mid,ans;
88         while(r-l>eps)
89         {
90             mid=(l+r)/2;
91             if(solve(mid))
92             r=(ans=mid)-eps;
93             else
94             l=mid+eps;
95         }
96         printf("%.9lf\n",ans);
97     }
98     return 0;
99 }

 

posted @ 2017-08-05 10:12  Wally的博客  阅读(206)  评论(0编辑  收藏  举报