二分的一些题目

题目1:技能升级

4656. 技能升级 - AcWing题库

解题

首先是贪心,每个技能的每次升级的点数构成一个等差数列,我们把所有的点数放在一起从大到小排序,计算前m个数的总和,就是我们可以获得的最大点数。

问题就转化成了,我们要怎么找到前m个数,也就是如何找到x,使得大于等于x的数的数量大于等于m,大于等于x+1的数的数量小于m,这个步骤可以用二分来做。

二分的check条件需要分别求出大于等于x和x+1的数的数量,利用等差数列的性质,对每一个技能,有:cur=a[i]-b[i]*k,大于等于x的数的个数就是(a[i]-cur)/b[i]向上取整。

最后利用等差数列的性质求前m项的和。

#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e5+10;
int n;
ll m;
int a[N],b[N];

bool check(int mid)
{
    ll cnt=0;
    for(int i=1;i<=n;i++)
        if(a[i]>=mid) cnt+=(a[i]-mid)/b[i]+1;
    return cnt>=m;
}
int main()
{
    scanf("%d%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    int l=0,r=1e6;
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    ll res=0;
    ll cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]>=l)
        {
            ll end=a[i]-(a[i]-l)/b[i]*b[i];
            ll c=(a[i]-l)/b[i]+1;
            res+=(a[i]+end)*c/2;
            cnt+=c;
        }
    }
    printf("%lld",res-(cnt-m)*l);
    
}

题目2:冶炼金属

4956. 冶炼金属 - AcWing题库

解题

要求能使a/v==b的最小v,相当于求能使a/v<=b的最大的a/v;

要求能使a/v==b的最大v,相当于求能使a/v>=b的最小的a/v。

#include<iostream>
using namespace std;
const int N=10010;
int n;
int a[N],b[N];
bool check1(int mid)
{
    for(int i=1;i<=n;i++)
    {
        if(a[i]/mid>b[i]) return false;
    }
    return true;
}
bool check2(int mid)
{
    for(int i=1;i<=n;i++)
    {
        if(a[i]/mid<b[i]) return false;
    }
    return true;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&b[i]);
    int l=1,r=1e9;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(check1(mid)) r=mid;
        else l=mid+1;
    }
    printf("%d ",l);
    l=1,r=1e9;
    //a/v>=b的最小值
    while(l<r)
    {
        int mid=(l+r+1)>>1;
        if(check2(mid)) l=mid;
        else r=mid-1;
    }
    printf("%d ",l);
}

  • 13
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值