您的位置:首页 > 其它

POJ - 3111 K Best(二分)

2015-11-17 14:08 204 查看
包含一些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\n",r[k]+1);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: