第三章: 二分、三分、01分数规划(7.19)
二分:
二分查找:
NC235558 牛可乐和魔法封印
单调序列 二分查找无需多说
NC24866 [USACO 2009 Dec S]Music Notes
求一个前缀和数组(显然是递增的)
二分前缀和数组求解即可
二分答案:
NC16462 [NOIP2015]跳石头
复习一下二分答案模板吧
#include<bits/stdc++.h> #define LL long long using namespace std; int d[50003],cha[50003]; int l,m,n; int check(int x) { int u=cha[1]; int num=0; for(int i=2;i<=n+1;++i) { if(u<x)u+=cha[i],num++; else u=cha[i]; } if(num>m)return 0; return 1; } int main() { scanf("%d%d%d",&l,&n,&m); int L=l+1,R=l; for(int i=1;i<=n;++i) { scanf("%d",&d[i]); cha[i]=d[i]-d[i-1]; L=min(L,cha[i]); } cha[n+1]=l-d[n]; L=min(L,cha[n+1]); int ans; while(L<=R) { int mid=(L+R)>>1; if(check(mid))ans=mid,L=mid+1; else R=mid-1; } printf("%d\n",ans); }
不知道为什么用l<=r的那种打法对,用l<r会出错
感觉对二分中边界条件了解的不是很清楚(然后果断换板子)
while(L+1<R) { int mid=(L+R)>>1; if(check(mid))ans=mid,L=mid; else R=mid; } ans=L; L表示最大的可行的 R表示最小的不可行的
01分数规划:
NC14662 小咪买东西
01分数规划+二分答案
对单位价值x进行二分 Σv - Σc * x = 0
如果选取的v和c使这个式子>0的话,即x < Σv / Σc(算出了答案可以比二分猜测的x大),继续变大x
依照这个式子得到每个物品的权值进行排序,选出最大的k个。进行Σv - Σc * x > 0的判断。
Σv - Σc * x < 0则说明x取大了,要缩小
最后的r就是第一个使得式子=0的
#include<bits/stdc++.h> #define LL long long #define INF 0x3f3f3f3f using namespace std; int n,k; double c[10005],v[10005],w[10005]; int check(double x) { for(int i=1;i<=n;++i) w[i]=v[i]-x*c[i]; sort(w+1,w+1+n,greater<double>()); double sum=0; for(int i=1;i<=k;++i) sum+=w[i]; return sum>0; } int main() { int T;scanf("%d",&T); while(T--) { scanf("%d%d",&n,&k); for(int i=1;i<=n;++i)scanf("%lf%lf",&c[i],&v[i]); double l=0,r=INF; double ans; double eps=1e-5; while (r-l>eps)//二分答案 { double mid=(l+r)/2.0; if(check(mid))l=mid; else r=mid; } ans=r; printf("%.0lf\n",ans); } }