二分的妙用 (A - Bookshelf Filling)

在进行第一次和学长进行组队赛的时候,碰见一个二分的题(但当时我们并没有看出来,学长他们都是二分过了,我们还在卡..)

题目链接:https://codeforces.com/gym/103688/problem/A

题目大意:

给你书架的高度,给你两种书(一高一低),并且分别给你他们的本数,要求用最小的宽度,将他们全放进去。

一开始我们通过画图,大概思路是先放短的书那一部分,看看在上边能够放置多少,然后将剩下的书,排一排,一本一本取,看看能再减少多少宽度。

由于我们做题不多,对二分的了解少。我们一开始把这个当成的一个思维题,通过解方程,处理了各种精度问题,最终花费大量时间,解决了问题;

时间复杂度O(1),速度很快,但是想的很慢。(

Code:

#include<bits/stdc++.h> 
#define ll long long
#define pll pair < ll , ll >
#define buff ios::sync_with_stdio(false)
using namespace std;
const int N = 1e6 + 10;
int main()
{
    buff;
    int t;
    cin>>t;
    while (t--) {
        ll a, b, n, m, h;
        cin>>a>>b>>n>>m>>h;
        if ((n / b) * (b - a) >= m - 1) {
            cout<<n + 1<<"\n";
            continue;
        }
        m = m - (n / b) * (b - a);
        if (b == h) {
            cout<<n + m<<"\n";
            continue;
        }
        
        ll cnt = (n+m)/h;
        ll cnt1=(m-1)/(h-b);
        cnt=min(cnt,cnt1);
        if(cnt*(h-b)>m-1&&cnt>0)cnt--;
        ll ans=n+m-(cnt*(h-b));
        m-=cnt*(h-b);
        if(ans-cnt*b>b&&m>1)
        {
            ll j1=(ans-cnt*b)-b;
            ll j2=m-1;
            j1=min(j1,j2);
            ans-=j1;
        }
        cout<<ans<<"\n"; 
        
        
        
//        if (((n + 1) / b) * (h - b) >= m - 1) {
//            cout<<n + 1<<"\n";
//            continue;
//        }
//        m = m -(((n + 1) / b) * (h - b));
//        ll len = b * (m / h);
//        ll cnt = (m / h) * h;
//        cout<<n + 1 + len + (m - cnt)<<"\n";
        
        
//        m = m - (n / b) * (h - b);
//        if (b == h) {
//            cout<<n + m<<"\n";
//            continue;
//        }
//        
//        ll x = (b - n % b);
//        if (x >= m) {
//            cout<<n + m<<"\n";
//            continue;
//        }
//        if (m - x <= h - b) {
//            cout<<n + x<<"\n";
//            continue;
//        }
//        m = m - x - (h - b);
//        ll len = b * (m / h);
//        ll cnt = (m / h) * h;
//        cout<<n + x + len + (m - cnt)<<"\n";
//        if (m >= b)
//        {
//            cout << n + x + min(m - b,h - b) * << "\n";
//            continue;
//        }
//        if(m < b)
//        {
//            cout << n + x + m << "\n";
//        }
    }
    return 0;
}

另一种写法是二分写法,直接通过对长度的二分,然后一次次缩短范围得到一个准确结果。

思路是一样的,只不过是用二分,让电脑进行判断长度是否合理,十分简便。

时间复杂度比上一个高,但是方便很多。

Code :

#include<bits/stdc++.h> 
#define ll long long
#define pll pair < ll , ll >
#define buff ios::sync_with_stdio(false)
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
ll a,b,n,m,h;
bool check(ll x)
{
    if((b - a) * (n / b) + x + (n + x) / b * (h - b) >= m)
    {
        return 1;
    }
    return 0;
}
int main()
{
    buff;
    ll t;
    cin >> t;
    while(t --)
    {
        cin >> a >> b >> n >> m >> h;
        ll l = 1,r = m;
        while(l < r)
        {
            ll mid = (l + r) >> 1;
            if(check(mid))
            {
                r = mid;
            }
            else
            {
                l = mid + 1;
            }
        } 
        cout << n + l << endl;
    }
}

虽然我们写的很慢,但是我们还是对那个方法比较骄傲(bushi

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值