[BZOJ1701] [Usaco2007 Jan]Cow School牛学校
[BZOJ1701] [Usaco2007 Jan]Cow School牛学校
可以说是一道变异的01规划
其实就是问是否存在方案满足不是选\(t/p\)最高的最优
设当前选了这些点,总答案是\(s\),即\(\sum t_i-p_i*s = 0\)
如果存在方案,则必然满足存在集合S \(\sum_{i \in S}t_i-p_i*s>0\)
然而,其实只要把选了的点中\(t_i-p_i*s\)最小的换成没选的中\(t_i-p_is\)中最大的,看看是否大于0即可
所以可以用斜率优化求最值,由于查询不具有单调性,所以要用 分治+单调栈+二分
两边求解后统计答案即可
const int N=5e4+10,P=1e9+7;
int n;
struct Node{
int a,b;
bool operator < (const Node __)const{ return 1.0*a/b>1.0*__.a/__.b; }
}A[N],B[N];
bool cmp(Node a,Node b){
return a.a<b.a;
}
double sa[N],sb[N];
double res[N];
double ma[N],mi[N];
double QA[N],QB[N];
int L,R;
void Solve1(int l,int r) {
if(l>=r) return;
int mid=(l+r)>>1;
rep(i,l,mid) B[i]=(Node){A[i].b,A[i].a};
sort(B+l,B+mid+1,cmp);
L=1,R=0;
rep(i,l,mid) {
while(L<R && (QB[R]-QB[R-1])/(QA[R]-QA[R-1])>(B[i].b-QB[R])/(B[i].a-QA[R]) ) R--;
QB[++R]=B[i].b;
QA[R]=B[i].a;
}
rep(i,mid+1,r) {
double t=res[i-1];
int bl=2,br=R,bmid,bres=1;
while(bl<=br) {
bmid=(bl+br)>>1;
if((QB[bmid]-QB[bmid-1])/(QA[bmid]-QA[bmid-1])<=t) bl=bmid+1,bres=bmid;
else br=bmid-1;
}
mi[i-1]=min(mi[i-1],QB[bres]-t*QA[bres]);
}
Solve1(l,mid);
Solve1(mid+1,r);
}
void Solve2(int l,int r) {
if(l>=r) return;
int mid=(l+r)>>1;
rep(i,mid+1,r) B[i]=(Node){A[i].b,A[i].a};
sort(B+mid+1,B+r+1,cmp);
L=1,R=0;
rep(i,mid+1,r) {
while(L<R && (QB[R]-QB[R-1])/(QA[R]-QA[R-1])<(B[i].b-QB[R])/(B[i].a-QA[R]) ) R--;
QB[++R]=B[i].b;
QA[R]=B[i].a;
}
rep(i,l,mid) {
double t=res[i];
int bl=2,br=R,bmid,bres=1;
while(bl<=br) {
bmid=(bl+br)>>1;
if((QB[bmid]-QB[bmid-1])/(QA[bmid]-QA[bmid-1])>=t) bl=bmid+1,bres=bmid;
else br=bmid-1;
}
ma[i]=max(ma[i],QB[bres]-t*QA[bres]);
}
Solve2(l,mid);
Solve2(mid+1,r);
}
int cnt;
int main(){
rep(i,1,n=rd()) A[i].a=rd(),A[i].b=rd();
sort(A+1,A+n+1);
rep(i,1,n) {
sa[i]=sa[i-1]+A[i].a,sb[i]=sb[i-1]+A[i].b;
ma[i]=-1e18;
mi[i]=1e18;
}
rep(i,1,n) res[i]=sa[i]/sb[i];
Solve1(1,n+1);
Solve2(1,n);
drep(i,n-1,1) if(ma[i]>mi[i]) cnt++;
printf("%d\n",cnt);
drep(i,n-1,1) if(ma[i]>mi[i]) printf("%d\n",n-i);
}