hdu6070

多校第四場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) ;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章