首页 > 代码库 > hdu 6070 线段树+二分

hdu 6070 线段树+二分

HDU - 6070 

题意:提交了n次题目,每个题目都是最后一次提交的时候AC的,现在求一个区间,这个区间的AC率是最低的(只考虑这个区间内的题目,同样区间内最后交的一遍是AC的),求最低的AC率

思路:AC率=提交次数/题目数目,即区间长度/题目种类,siz[l,r]/(r-l+1)=p(siz[l,r]表示l r区间内的不同题目的个数,p表示AC率), 把式子做一下调整,siz[l,r]+p*l=p(r+1),二分p(0-1)用线段树维护siz[l,r]+l*p ,然后枚举r,每次更新,因为l交给线段树维护了,所以不需要考虑l的位置,题解真是666,重新认识了线段树,感谢飞哥的大力帮助@jhz033,不然我还不知道线段树维护的是什么东西,这个题式子好写,但是思路难想,代码也好拍,但是余味还可以回味一年,这种思想还是值得去品味的,这波不亏

AC代码:

#include "iostream"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#pragma comment(linker, "/STACK:102400000,102400000")
#define ll long long
#define endl ("\n")
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a,x) memset(a,x,sizeof(a))
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define ft (frist)
#define sd (second)
#define lrt (rt<<1)
#define rrt (rt<<1|1)
using namespace std;
const long long INF = 1e18+1LL;
const int inf = 1e9+1e8;
const double eps=1e-4;
const int N=6e4+100;
const ll mod=1e9+7;

int n,a[N];
double MID;
struct TREE{
    int lazy[N<<2];
    double mi[N<<2];
    void push_up(int rt){
        mi[rt]=min(mi[lrt], mi[rrt]);
    }
    void push_down(int rt){
        mi[lrt]+=lazy[rt];
        mi[rrt]+=lazy[rt];
        lazy[lrt]+=lazy[rt];
        lazy[rrt]+=lazy[rt];
        lazy[rt]=0;
    }
    void creat(int rt, int l, int r){
        lazy[rt]=0;
        if(l==r){
            mi[rt]=MID*l;
            return;
        }
        int mid=l+r>>1;
        creat(lrt, l, mid);
        creat(rrt, mid+1, r);
        push_up(rt);
    }
    void update(int rt, int l, int r, int L, int R){
        if(L<=l && R>=r){
            mi[rt]+=1;
            lazy[rt]+=1;
            return;
        }
        if(lazy[rt]!=0) push_down(rt);
        int mid=l+r>>1;
        if(L<=mid) update(lrt, l, mid, L, R);
        if(R>mid) update(rrt, mid+1, r, L, R);
        push_up(rt);
    }
    double query(int rt, int l, int r, int L, int R){
        if(L<=l && R>=r){
            return mi[rt];
        }
        if(lazy[rt]!=0) push_down(rt);
        int mid=l+r>>1;
        double ans=99999999999;
        if(L<=mid) ans=min(ans,query(lrt, l, mid, L, R));
        if(R>mid) ans=min(ans,query(rrt, mid+1, r, L, R));
        return ans;
    }
}tree;

bool check(){
    int pre[N]; mem(pre,0);
    tree.creat(1,1,n);
    for(int i=1; i<=n; ++i){
        tree.update(1, 1, n, pre[a[i]]+1, i);
        double f=tree.query(1,1,n,1,i);
        if(f<=MID*(i+1)) return 1;
        pre[a[i]]=i;
    }
    return 0;
}
int main(){
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        for(int i=1; i<=n; ++i){
            cin>>a[i];
        }
        double l=0, r=1, ans=0;
        while(r-l>=eps){
            MID=(l+r)/2;
            if(check()){
                ans=MID;
                r=MID;
            }
            else l=MID;
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

hdu 6070 线段树+二分