题目
题解
01分数规划
0-1 分数规划
t1 * x1 + t2 * x2 + ... + tn * xn
r = ---------------------------------
c1 * x1 + c2 * x2 + ... + cn * xn
给定t[1..n], c[1..n], 求x[1..n]使得sigma(xi)=k且r最大(小).
为了让r最大, 先设计子问题z(r) = (t1 * x1 + .. + tn * xn) - r * (c1 * x1 + .. + cn * xn);
假设r的最优值为R. 则有:
z(r) < 0 当且仅当 r > R;
z(r) = 0 当且仅当 r = R;
z(r) > 0 当且仅当 r < R;
于是可二分求R.
#include<bits/stdc++.h>
using namespace std;
typedef double D;
const int N=50002;
const D eps=1e-6;
struct node{
int p,w;
D c;
}a[N];
int n,k,i,G,x,y,xx,yy;
D l,r,mid;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
int x=0,fl=1;char ch=gc();
for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
return x*fl;
}
bool cmp(node a,node b){
return a.c>b.c;
}
bool check(int &x,int &y,D p){
for (int i=0;i<n;i++) a[i].c=a[i].p-p*a[i].w;
nth_element(a,a+k-1,a+n,cmp);
x=0;y=0;D z=0;
for (int i=0;i<k;i++){
x+=a[i].p;y+=a[i].w;
z+=a[i].c;
}
return z>=0;
}
int main(){
n=read();k=read();
for (i=0;i<n;i++) a[i].w=read(),a[i].p=read();
l=0;r=2e9;
while (r-l>eps){
mid=(l+r)/2;
if (check(x,y,mid)) l=mid,xx=x,yy=y;
else r=mid;
}
G=__gcd(xx,yy);
xx/=G;yy/=G;
printf("%d/%d",xx,yy);
}