2020ICPC·小米 网络选拔赛第一场 F题 Design Problemset

这是第一道接近做出来的二分,唯一差的就是没有考虑数据范围(因为我这个菜鸡能做的题很少会让我卡long long)。

这个题的分组存在一个很明显的临界值,所以开始考虑二分。然后开始考虑check怎么想(要不是队友解释了题目,我估计看样例就要long long)。

我当时考虑的是,全取左端点,然后把多余的部分保留下来,进行判断。(考虑右端点不会爆long long)

因为每一个问题库还有一个范围,所以 问题库/分组 的值最大也不能超过他自身的右端点r,多余的部分就可以用

sum += min((a[i].ri  -a[i].li )*m , a[i].s -a[i].li*m);

这样就可以写出最关键的判断条件,minn是所有左端点的总和,sum是所有多出来的部分。

if(minn+sum/m>=l&&minn<=r){
		return true;
	}

我这里写了minn<=r,也就是问题库范围左端点总和是小于要求的右端点的,那么就可以不用进行特判了(没那个脑子想特判了)

我做这个题有三个点需要注意:

一个是数据在1e9的,优先考虑从小的方面开始找,不然很有可能就爆了longlnog。
第二个是二分算法,把右边界开到1e18,我最开始写了1e9,简直在找死。
第三个是爆了long long,直接尝试一发int 128 ,long double 也可以把问题避免掉 。

最后考虑了一下为什么要写long double,不一定对:
因为考虑数据极端情况,每一个组都是0 1 ,一共可以有1e9组问题,那么问题集就能被开到1e18,那么sum最大值就是1e27。

总之,像如这种写了1e18,还有乘一个什么东西的,还是开大点吧。

能研究出这么做对的,还是靠一个队交了12发,不然我都以为这个题我做法错了,估计他们范围也改的很崩溃吧hhh.

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
typedef long long ll;
struct node{
    ll s,li,ri,ti;
};
node a[N]; 
ll n,l,r;
bool check(long double m){
    if(m==0) return true;
     
    long double sum = 0;
    long double minn = 0;
      
    for(int i = 1;i<=n;i++){
        minn  += a[i].li;
         
        if(a[i].li !=0){   //这地方写乘就不用特判了
            if(a[i].s/a[i].li <m){
                return false;
            }
        }
         
        sum +=min( (a[i].ri  -a[i].li )*m , a[i].s -a[i].li*m );
             
    }
    //cout<<m<<" "<<sum<<endl;
    if(minn+sum/m>=l&&minn<=r){
        return true;
    }
    else{
        return false;
    }
}
int main(){
 
    scanf("%lld%lld%lld",&n,&l,&r);
     
    for(int i = 1;i<=n;i++){
        scanf("%lld",&a[i].s );
    }
     
    for(int i = 1;i<=n;i++){
        scanf("%lld%lld",&a[i].li ,&a[i].ri );
    }
 
    ll s = 0,t =  1e18;
    while(s<=t){
        long double m = (s+t)/2;
         
        if(check(m)==true){
            s = m+1;
        }
        else{
            t = m-1;
        }
    //  cout<<s<<" "<<t<<endl;
    }
     
    printf("%lld",t);
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值