hdu6070

xiaoxiao2021-02-28  102

多校第四场1004

Dirt Ratio 这个题意提炼出来就是让我们求一个序列中有区间中的不同数字和该区间长度的比值的最小值。 这个题目十分巧妙,因为之前刚刚写过codeforces上的一个类似题目,详见这里 : Codeforces Round #426 (Div. 2) D. The Bakery 当时做多校的时候有往这个方面去想但是又不知道怎么去做,看了题解后才有总结。 首先我们知道类似这种求不同颜色的题目,我们有一个方法就是维护一个S[],每当枚举到一个i时,我们记录num[i]最近一次出现的位置p,[p+1 , i]这段里的S都+1。这时,S[j]里面存的是从j到当前枚举的i里面有多少个不同的数字。 所以我们可以利用这个性质把这道题往这个方向上去靠,当前我们计算到i时,实际上就是要求 Sj/(i-j+1)的一个最小值。但是到这里用一般的数据结构应该还是不太好求,然后我们再试着把i和j分开。假设我们知道这个最小值minx = Sj/(i-j+1) => minx*i = Sj + minx* ( j-1) ,分开之后就好求很多了,当前枚举到i的时候,在前面里面找是否能有满足条件的j即可。然后这个最小值我们可以通过二分来枚举。

#include<cmath> #include<algorithm> #include<cstring> #include<string> #include<set> #include<map> #include<time.h> #include<cstdio> #include<vector> #include<list> #include<stack> #include<queue> #include<iostream> #include<stdlib.h> using namespace std; #define LONG long long const LONG INF=0x3f3f3f3f; const LONG MOD=1e9+ 7; const double PI=acos(-1.0); #define clrI(x) memset(x,-1,sizeof(x)) #define clr0(x) memset(x,0,sizeof x) #define clr1(x) memset(x,INF,sizeof x) #define clr2(x) memset(x,-INF,sizeof x) #define EPS 1e-10 #define lson l , mid , rt<< 1 #define rson mid + 1 ,r , (rt<<1)+1 #define root 1, n , 1 int take[61000] ; int a[65000] ; double tree[62000*4] ; double lazy[62000<<2]; void Push_up(int rt) { tree[rt] = min(tree[rt<<1] , tree[rt<<1|1] ) ; } void Push_Down(int rt ) { lazy[rt<<1] += lazy[rt] ;tree[rt<<1|1] += lazy[rt ] ; tree[rt<<1] += lazy[rt] ;lazy[rt<<1|1] += lazy[rt] ; lazy[rt] = 0 ; } void Update(int L ,int R ,int l , int r , int rt ,double x) { if(L <= l && r<= R) { tree[rt] += x;lazy[rt] += x;return ; } Push_Down(rt) ;int mid = (l + r) /2 ; if(L <= mid)Update(L,R,lson ,x ) ; if(R > mid )Update(L ,R ,rson , x) ; Push_up(rt) ; } double Min(double a ,double b) { return a< b?a:b ; } double Que(int L ,int R , int l, int r , int rt ) { if(L <= l &&r <=R) return tree[rt] ; int mid = (l+r) / 2; Push_Down(rt) ; double res =1000000000.0; if(L <= mid)res =Min(res , Que(L , R,lson ) ) ; if(R > mid) res = Min(res , Que(L ,R ,rson ) ) ; return res ; } int main() { int T ; int n ; cin >> T ; while(T --) { cin >> n ; for(int i =1; i<= n ; ++i) scanf("%d",&a[i] ) ; double l = 0 , r = 1.000 ; double mid ; for(;fabs(r -l ) >= 0.0001; ) { mid = ( l + r ) / 2; clr0(take) ; for(int i = 1; i<= n * 4 ; ++ i)tree[i] = 0,lazy[i] = 0 ; int judge = 0 ; for(int i = 1;i <= n ; ++ i) { int t ; if(take[a[i]] == 0) take[a[i]] = i , t = 0; else t = take[a[i]] , take[a[i] ] = i ; Update(i , i ,root , (double) (i-1) * mid ) ; Update(t+1 , i , root ,1.0) ; double res = Que(1,i,root) ; if(res <= (double)i*mid ) { judge = 1;break ; } } if(judge)r = mid ; else l = mid ; } printf("%.6lf\n",mid) ; } }
转载请注明原文地址: https://www.6miu.com/read-53095.html

最新回复(0)