BZOJ1701 : [Usaco2007 Jan]Cow School牛学校
枚举剩下的分数个数$k$,设最高的$k$个分数和的分子分母分别为$U$和$D$。
那么在选了的里面找到$A=\min(Dt[x]-Up[x])$,没选的里面找到$B=\max(Dt[x]-Up[x])$。
如果$A<B$,则可以更大。
对于$A,B$的计算,可以利用决策单调性分治求解。
时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> typedef long long ll; const int N=50010; const ll inf=1LL<<60; int n,i,ans,q[N];ll f[N],g[N]; struct P{int t,p;}a[N],b[N]; inline bool cmp(const P&a,const P&b){return a.t*b.p>b.t*a.p;} void getf(int l,int r,int dl,int dr){ int m=(l+r)>>1,dm; f[m]=inf; for(int i=dl;i<=m&&i<=dr;i++){ ll t=1LL*a[i].t*b[m].p-1LL*a[i].p*b[m].t; if(t<f[m])f[m]=t,dm=i; } if(l<m)getf(l,m-1,dl,dm); if(r>m)getf(m+1,r,dm,dr); } void getg(int l,int r,int dl,int dr){ int m=(l+r)>>1,dm; g[m]=-inf; for(int i=dr;i>m&&i>=dl;i--){ ll t=1LL*a[i].t*b[m].p-1LL*a[i].p*b[m].t; if(t>g[m])g[m]=t,dm=i; } if(l<m)getg(l,m-1,dl,dm); if(r>m)getg(m+1,r,dm,dr); } int main(){ scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d%d",&a[i].t,&a[i].p); std::sort(a+1,a+n+1,cmp); for(i=1;i<=n;i++)b[i].t=b[i-1].t+a[i].t,b[i].p=b[i-1].p+a[i].p; getf(1,n-1,1,n),getg(1,n-1,1,n); for(i=1;i<n;i++)if(f[i]<g[i])q[++ans]=n-i; for(printf("%d\n",ans),i=ans;i;i--)printf("%d\n",q[i]); return 0; }