包含一些ai和bi的集用S来表示,x = max(sigma(ai)/sigma(bi),i 属于S) ,k 表示S的大小,k= |S|。
x和k之间具有单调性。k0 < k1 → x0 ≥ x1。单调性对x(k)的反函数k(x)也成立。现在的问题是k已经给出,
那么猜测一个x,通过和sigma(ai)/sigma(bi) 作差得到大小关系以便收敛区间。
要求x可以做一点变形sigma(ai)/sigma(bi) - k*x → sigma(ai - x*b),x是max值,和一个常数作差以后也是最大的,
因此选取前k大元素ai - x*b求和就可以得到差值。
(还有一种很迷的迭代法也可以收敛
/********************************************************* * ------------------ * * author AbyssalFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<vector> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> using namespace std; const int maxn = 1e5; int n, k; struct Query { int v,w; double key; }q[maxn]; int r[maxn]; struct cmp { bool operator()(int a,int b){ return q[a].key > q[b].key; } }; double cal(double x) { for(int i = 0; i < n; i++){ q[r[i]].key = q[r[i]].v-x*q[r[i]].w; } nth_element(r,r+k,r+n,cmp()); double re = 0; for(int i = 0; i < k; i++){ re += q[r[i]].key; } return re; } const double eps = 1e-11; //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif while(~scanf("%d%d",&n,&k)){ double lb = 0, ub = 0, md, re; for(int i = 0; i < n; i++){ scanf("%d%d",&q[i].v,&q[i].w); r[i] = i; ub = max(ub,(double)q[i].v/q[i].w); } for(int i = 100; i--;){ md = (lb+ub)/2; re = cal(md); if(re > eps) lb = md; else if(re < -eps) ub = md; else break; } k--; for(int i = 0; i < k; i++){ printf("%d ",r[i]+1); } printf("%d ",r[k]+1); } return 0; }