luoguP10505
\(luogu\)
思路
纯贪心(其实不用看的)
这是在机房,我左右两边两个巨佬提出的,水过了第 15 行后就被老师 hack 了,俩人讨论后发现贪心有局限性
01 分数规划(正解)
01 分数规划是什么?
01 分数规划多用于求解类似于给出 \(a,b\) 数组,求选择 \(k\) 个数 \(p\),使得 \(\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{n} b_{p_i}}\) 最大化。
01 分数规划怎么求?
01 分数规划多使用二分求解,下面推一下 check:
首先有
\[\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{k} b_{p_i}}> mid
\]
移项得
\[\frac{\sum_{i = 1}^{k} a_{p_i}}{\sum_{i = 1}^{k} b_{p_i}}-mid>0
\]
再次移项得
\[{\sum_{i = 1}^{k} a_{p_i}}-mid\times{\sum_{i = 1}^{k} b_{p_i}}>0
\]
化简得
\[{\sum_{i = 1}^{k} a_{p_i}-mid\times b_{p_i}}>0
\]
引入本题
这就是一个 01 分数规划板子,直接分数二分套板子就好了
code
#include<bits/stdc++.h>
//#define int long long
#define esp 1e-6//精度差
using namespace std;
inline int read(){
char c=getchar();
int ret=0,f=1;
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ret=(ret<<3)+(ret<<1)+c-'0';
c=getchar();
}return ret*f;
}
inline void write(int x,int op){
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10,0);
putchar((char)(x%10+'0'));
if(op){
if(op>0)puts("");
if(op<0)putchar(' ');
if(op==0)puts("114514");
}
}
const int N=1e3+10;
int n,k;
double a[N],b[N];
bool cmp(double x,double y){return x>y;}
bool check(double x){
double ret=0,c[N];
for(int i=1;i<=n;i++)c[i]=a[i]-x*b[i];
sort(c+1,c+1+n,cmp);//排序,为贪心做准备
for(int i=1;i<=n-k;i++)ret+=c[i];//贪心的选取最大
return ret>0;
}
int main(){
n=read(),k=read();
while(n||k){
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)b[i]=read();
double l=0.0,r=114.0;//二分上下界
while(r-l>=esp){
double mid=(l+r)/2.0;
if(check(mid))l=mid;
else r=mid;
}printf("%.0lf\n",100*l);//按题目要求输出l*100
n=read(),k=read();
}
return 0;
}//*~完结撒花~*

浙公网安备 33010602011771号