一开始还以为是一道分数规划,后来发现自己看错题了,
然后成功入坑
题目是要求先按照$t_i/p_i$从小到大排序,然后删除前$d$个后求出剩下的$\frac{\sum^{n-d+1}_{i=1}t_i}{\sum^{n-d+1}_{i=1}p_i}$,如果当前的删除方法不是最优的(即能删除其它$d$个数使原式的值变大的话),则输出这个$d$
首先排序自不必说,排完序之后基础的式子的值也就求出来了
那么问题就在于如何判断当前的删除方法是不是最优的
为了方便我们将数据从大到小排序
我们假设当前取了前$k$个最大的
并设$T=t_1+t_2+\cdots+t_k,P=p_1+p_2+\cdots+p_k$
那么题目就是求是否存在$i,j$,满足$\frac{T-t_i+t_j}{P-p_i+p_j}>\frac{T}{P}$(其中$i\in \lbrace1,2,\cdots,k \rbrace,j\notin \lbrace1,2,\cdots,k \rbrace$)
将式子变形得$P*t_i-T*p_i<P*t_j-T*t_i$
所以我们只要找出$P*t_i-T*p_i$的$min$,以及$P*t_j-T*p_j$的$max$
这时我们再来算一算时间复杂度
我们在枚举前$k$个最大的数时需要$O(n)$的时间,
因此我们在处理最大值与最小值时只能用$O(logn)$的时间复杂度
但由于我们的$与T_i与P_i$是已经排好序的,所以我们可以用二分来处理这个最大值与最小值
感觉洛谷上这题给黑题是不是太高看了(逃
1 #include<iostream> 2 #include<string> 3 #include<string.h> 4 #include<stdio.h> 5 #include<algorithm> 6 #include<vector> 7 #include<queue> 8 #include<map> 9 using namespace std; 10 const long long inf=(long long)1e18; 11 struct node{ 12 long long t,p; 13 }a[50050],b[50050]; 14 int n,ans[50050]; 15 long long mind[50050],maxd[50050]; 16 17 bool cmp(node x,node y) 18 { 19 return x.t*y.p>x.p*y.t; 20 } 21 22 void getmin(int l,int r,int pl,int pr) 23 { 24 int i,mid=(l+r)>>1,pos; 25 for (i=pl;i<=mid&&i<=pr;i++) 26 { 27 long long tmp=a[i].t*b[mid].p-a[i].p*b[mid].t; 28 if (tmp<mind[mid]) {mind[mid]=tmp;pos=i;} 29 } 30 if (l<mid) getmin(l,mid-1,pl,pos); 31 if (r>mid) getmin(mid+1,r,pos,pr); 32 } 33 34 void getmax(int l,int r,int pl,int pr) 35 { 36 int i,pos,mid=(l+r)>>1; 37 for (i=pr;i>mid&&i>=pl;i--) 38 { 39 long long tmp=a[i].t*b[mid].p-a[i].p*b[mid].t; 40 if (tmp>maxd[mid]) {maxd[mid]=tmp;pos=i;} 41 } 42 if (l<mid) getmax(l,mid-1,pl,pos); 43 if (r>mid) getmax(mid+1,r,pos,pr); 44 } 45 46 int main() 47 { 48 scanf("%d",&n); 49 int i; 50 for (i=1;i<=n;i++) scanf("%lld%lld",&a[i].t,&a[i].p); 51 sort(a+1,a+1+n,cmp); 52 b[0].t=0;b[0].p=0; 53 for (i=1;i<=n;i++) 54 { 55 b[i].t=b[i-1].t+a[i].t; 56 b[i].p=b[i-1].p+a[i].p; 57 } 58 for (i=1;i<=n;i++) {mind[i]=inf;maxd[i]=-inf;} 59 getmin(1,n-1,1,n);getmax(1,n-1,1,n); 60 int pos=0; 61 for (i=1;i<n;i++) if (mind[i]<maxd[i]) ans[++pos]=n-i; 62 printf("%d\n",pos); 63 for (i=pos;i>=1;i--) printf("%d\n",ans[i]); 64 return 0; 65 }