https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1257
很裸的分数规划 二分答案 得如下转换
sum(pi)/sum(wi)=ans? => sum(pi)=ans*sum(wi)? => sum(pi-ans*wi)=0?
发现ans具有二分性 如果ans太小则sum(pi-ans*wi)会小于0
二分出ans后按pi-ans*wi升序排序 取前k大的 要是凑不够0那就是太小 凑的够那就说明ans还有上升空间
using namespace std;
const double N=1e18;
const double eps=1e-6;
const int maxn=50010;
struct node
{
ll w;
ll p;
double v;
};
node ary[maxn];
ll a,b,gcd;
int n,k;
bool cmp(node n1,node n2)
{
return (double)(n1.p)-n1.v*(double)(n1.w)>(double)(n2.p)-n2.v*(double)(n2.w);
}
bool judge(double lim)
{
double sum;
int i;
for(i=1;i<=n;i++) ary[i].v=lim;
sort(ary+1,ary+n+1,cmp);
sum=0.0;
for(i=1;i<=k;i++) sum+=(double)(ary[i].p)-ary[i].v*(double)(ary[i].w);
if(sum<0.0) return false;
else
{
a=0,b=0;
for(i=1;i<=k;i++) a+=ary[i].p;
for(i=1;i<=k;i++) b+=ary[i].w;
gcd=__gcd(a,b);
a/=gcd,b/=gcd;
return true;
}
}
int main()
{
double l,r,m;
int i;
scanf("%d%d",&n,&k);
for(i=1;i<=n;i++) scanf("%lld%lld",&ary[i].w,&ary[i].p);
l=0.0,r=N;
while(r-l>eps)
{
m=(l+r)/2.0;
if(judge(m)) l=m;
else r=m;
}
printf("%lld/%lld\n",a,b);
return 0;
}