【二分-贪心】问题集合

二分这类问题 通常需要猜结论乱搞,解决此类问题的方法,就是见多识广

Q1

题意是说一个船会随风飘动,风的方向有周期。船每天也可以选择往一个方向自由航行,效果和风叠加,类似矢量。问最少多少天能到目的地。

做法是二分天数。天数定了,船如果不动,终点就是定了的。再此基础上船还可以走 天数 这么多步。如果和目的地的距离小于这个步数就缩减天数。

单调性:对于mid天,如果能达到,那么大于mid天也肯定能达到,因为多出的天数船可以想办法每天抵消风的影响呆在原地。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 233;
int n, dirx[maxn], diry[maxn], desx, desy,inix,iniy;
string s;
int main()
{
    cin >> inix >> iniy >> desx >> desy;
    if(inix == desx && iniy == desy)
    {cout<<0;return 0;}
    cin >> n >> s;
    for(int i = 1; i <= n; i++ )
    {
        if(s[i - 1] == 'U') diry[i] = 1;
        if(s[i - 1] == 'D') diry[i] = -1;
        if(s[i - 1] == 'L') dirx[i] = -1;
        if(s[i - 1] == 'R') dirx[i] = 1;
    }
    for(int i = 2; i <= n; i++ )
    {
        dirx[i] += dirx[i - 1];
        diry[i] += diry[i - 1];
    }
    ll l = 1,r = 1LL << 63 - 1;
    while(l < r)
    {
        ll mid = (l + r) >> 1;
        ll tx = (mid / n) * dirx[n] + inix + dirx[mid % n];
        ll ty = (mid / n) * diry[n] + iniy + diry[mid % n];
        if(abs(desx - tx) + abs(desy - ty) <= mid) r = mid;
        else l = mid + 1;
    }
    if(r == 1LL << 63 - 1) cout << -1;
    else cout << l;
}

Q2

题意说有 m 个任务, n 杯咖啡,第 i 杯咖啡可以解决 ci 个任务。每天第二杯咖啡效果会 – 1 ,第二杯 – 2 以此类推。直到为 0 ,效果不能为负数。问最少多少天能完成任务。

做法是排序咖啡效果。二分天数,在天数定了的基础上每天第一杯都是效果最好的咖啡,第二杯次之……如果咖啡用完能完成任务,缩减天数。

这个其实需要考到在天数定了的情况下,每天喝更多杯咖啡不会比平均每天和一样多杯咖啡更优((-1-2-3)(-1) < (-1-2)(-1-2))。效果更差的排在前面不会比更好的排在前面更优(因为效果不能为负数,所以效果更差的排在后面的当他没效果的时候损失越小)

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 233;
typedef long long ll;
ll n, m;
ll a[maxn],b[maxn];
bool cmp(const int &a, const int &b)
{
    return a>b;
}
int main()
{
    ll tot = 0,cnt = 0;
    cin >> n >> m;
    for(int i = 1;i <= n; i++ )
    {
        cin >> a[i];
        tot += a[i];
        cnt ++ ;
    }
    sort(a + 1, a + 1 + n, cmp);
    if(tot < m) 
    {
        cout<< -1;
        return 0;
    }
    ll l = 1,r = n;
    while(l < r)
    {
        ll mid = (l + r) >> 1;
        ll k=1,res=0,q=0;
        while(k<=n)
        {
            for(int i=1;i<=mid;i++) 
            {
                res+=max(0LL,a[k]-q);
                k++;
                if(k>n) break;
            }
            q++;
        }
        if(res>=m) r=mid;
        else l=mid+1;
    }
    cout<< l;
}

Q3

标题即传送门

发表评论

电子邮件地址不会被公开。 必填项已用*标注