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

xiaoxiao2021-02-28  113

Description 给出n次提交的题目编号,对于一个区间,假设该区间中每个题的最后一次提交是AC,之前都是WA,求所有区间中AC数/提交次数最小值 Input 第一行一整数T表示用例组数,每组用例首先输入一整数n表示总提交次数,之后n个整数a[1]~a[n]表示这n次提交的题目编号(1<=T<=15,1<=n<=6e4,1<=a[i]<=n) Output 输出AC数/提交次数的最小值 Sample Input 1 5 1 2 1 2 3 Sample Output 0.5000000000 Solution 二分答案,设二分值为mid,num(l,r)表示区间[l,r]中的不同编号的题目数(即为AC数),那么只要存在一个区间[l,r]满足num(l,r)/(r-l+1)<=mid那么说明该二分值合法,可以寻求更小的二分值当答案,否则要找更大的二分值去找合法解,对上式转化一下变成num(l,r)+mid*l<=mid*(r+1),当区间右端点由r-1变成r时,所有num(l,r)中只有num(pre(a[r])+1,r)~num(r,r)加一,其他的均不变(pre(a[r])表示a[r]上一次出现的位置,如果a[r]没有出现则pre(a[r])=0),故可以用线段树维护num(l,r)+mid*l的最小值,每次插入的时候对pre(a[r])+1~r做区间加一操作,每次判合法只需将区间1~r中最小值拿出来和mid*(r+1)比较即可,由于精度要求是1e-4,所以二分14次即可,时间复杂度O(14nlogn) Code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; namespace fastIO { #define BUF_SIZE 100000 //fread -> read bool IOerror=0; inline char nc() { static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; if(p1==pend) { p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); if(pend==p1) { IOerror=1; return -1; } } return *p1++; } inline bool blank(char ch) { return ch==' '||ch=='\n'||ch=='\r'||ch=='\t'; } inline void read(int &x) { char ch; while(blank(ch=nc())); if(IOerror)return; for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0'); } #undef BUF_SIZE }; using namespace fastIO; const int INF=1e9,maxn=60001; #define ls (t<<1) #define rs ((t<<1)|1) double Min[maxn<<2]; int Lazy[maxn<<2]; void push_up(int t) { Min[t]=min(Min[ls],Min[rs]); } void build(int l,int r,int t,double x) { Lazy[t]=0; if(l==r) { Min[t]=x*l; return ; } int mid=(l+r)/2; build(l,mid,ls,x),build(mid+1,r,rs,x); push_up(t); } void push_down(int t) { if(Lazy[t]) { Lazy[ls]+=Lazy[t],Min[ls]+=Lazy[t], Lazy[rs]+=Lazy[t],Min[rs]+=Lazy[t]; Lazy[t]=0; } } void update(int L,int R,int l,int r,int t,int v) { if(L<=l&&r<=R) { Lazy[t]+=v,Min[t]+=v; return ; } push_down(t); int mid=(l+r)/2; if(L<=mid)update(L,R,l,mid,ls,v); if(R>mid)update(L,R,mid+1,r,rs,v); push_up(t); } double query(int L,int R,int l,int r,int t) { if(L<=l&&r<=R)return Min[t]; push_down(t); int mid=(l+r)/2; double ans=INF; if(L<=mid)ans=min(ans,query(L,R,l,mid,ls)); if(R>mid)ans=min(ans,query(L,R,mid+1,r,rs)); return ans; } int T,n,a[maxn],pre[maxn],pos[maxn]; bool check(double x) { build(1,n,1,x); for(int i=1;i<=n;i++) { update(pre[i]+1,i,1,n,1,1); if(query(1,i,1,n,1)<=x*(i+1))return 1; } return 0; } int main() { read(T); while(T--) { read(n); memset(pos,0,sizeof(pos)); for(int i=1;i<=n;i++) { read(a[i]); pre[i]=pos[a[i]],pos[a[i]]=i; } double l=0,r=1,mid; int t=14; while(t--) { mid=0.5*(l+r); if(check(mid))r=mid; else l=mid; } printf("%.5f\n",mid); } return 0; }
转载请注明原文地址: https://www.6miu.com/read-73262.html

最新回复(0)