第三章: 二分、三分、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);
    }
}
小咪买东西
posted @ 2022-07-20 22:33  yyys  阅读(20)  评论(0编辑  收藏  举报