ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF847E Packmen 题解

2021-11-05 11:01:11  阅读:157  来源: 互联网

标签:CF847E int 题解 peo cnt2 向右走 物品 Packmen pack


  • 奇怪的东西

  • 题意

    今有一区间,人,物具陈其上,间或亦有空.其人可左右徙于上.求让人的移动轨迹覆盖所有物品的情况下,人移动的路程的最大值的最小值.

  • 题解

    根据题意,显然看出是二分.再考虑一个人的走法:

    • 向左走,不回头

    • 向右走,不回头

    • 向左再向右,左边重复走

    • 向右再向左,右边重复走

若我们从左到右把人扫一遍,必然要保证先把左边的没走到的物品走到,同时在还有步数的情况下向右走.

这样会WA on #7 ,原因在于先向右走再向左走到第一个没走到的物品可能更优,因为重复的部分可能更少.

考虑分类讨论:用一个物品指针指向还没走到的最靠左的物品

  1. 步数不够到达最左边的没走到的物品\(\to\)直接return false

  2. 步数只能到最左边的物品,无法向右走\(\to\)把物品指针向右更新到人右边

  3. 步数很充足\(\to\)在3,4两种走法中取最优解

  4. 指针在人右边\(\to\)把物品指针尽可能向右更新

结束后判断指针是否大于\(Cnt_{package}\)即可

这样就又WA了,原因在于二分的右边界应当是\(\frac{3n}{2}\),即只有一个人在正中间,先向某方向然后再折返的答案,程序里为了简单写成了\(2n\).

最终复杂度:\(O(Cnt_{people}\log2n)\),明显快于\(O(n\log2n)\).

  • 代码

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100005;
int n, L, R, cnt1, cnt2;
int peo[N], pack[N];
string s;
bool check(int k)
{
    int await_pick = 1;
    for (int i = 1; i <= cnt1; i++)
    {
        int start_pos = await_pick;
        if (await_pick > cnt2)
            return true;
        if (pack[start_pos] < peo[i])
        {
            if (pack[start_pos] < peo[i] - k)//第一种情况
                return false;
            if (k <= peo[i] - pack[start_pos] + 1)//第二种情况
            {
                while (pack[await_pick + 1] <= peo[i] && await_pick <= cnt2 && pack[await_pick + 1] <= peo[i + 1])
                    await_pick++;
                if (pack[await_pick] <= peo[i] && pack[await_pick] <= peo[i + 1])
                    await_pick++;
            }
            else
            {
                if (k > (2 * (peo[i] - pack[start_pos])))
                {//第三种情况,先向左走
                    int temp = k - (2 * (peo[i] - pack[start_pos]));
                    while (pack[await_pick + 1] <= peo[i] + temp && await_pick <= cnt2 && pack[await_pick + 1] <= peo[i + 1])
                        await_pick++;
                    if (pack[await_pick] <= peo[i] + temp && pack[await_pick] <= peo[i + 1])
                        await_pick++;
                }
                if (peo[i] + (k + pack[start_pos] - peo[i]) / 2 >= pack[await_pick])
                {//第三种情况,先向右走
                    int temp = (k + pack[start_pos] - peo[i]) / 2;
                    while (pack[await_pick + 1] <= peo[i] + temp && await_pick <= cnt2 && pack[await_pick + 1] <= peo[i + 1])
                        await_pick++;
                    if (pack[await_pick] <= peo[i] + temp && pack[await_pick] <= peo[i + 1])
                        await_pick++;
                }
            }
        }
        else
        {//第四种情况
            while (pack[await_pick + 1] <= peo[i] + k && await_pick <= cnt2 && pack[await_pick + 1] <= peo[i + 1])
                await_pick++;
            if (pack[await_pick] <= peo[i] + k && await_pick <= cnt2 && pack[await_pick] <= peo[i + 1])
                await_pick++;
        }
    }
    if (await_pick > cnt2)
        return true;
    else
        return false;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> s;
    for (int i = 0; i < s.length(); i++)
    {
        if (s[i] == 'P')
            peo[++cnt1] = i + 1;
        if (s[i] == '*')
            pack[++cnt2] = i + 1;
    }
    peo[cnt1 + 1] = 0x7fffffff;
    pack[cnt2 + 1] = 0x7fffffff;
    L = 1, R = 2 * n;//注意二分边界
    while (L <= R)
    {
        int mid = (L + R) / 2;
        if (check(mid))
            R = mid - 1;
        else
            L = mid + 1;
    }
    cout << L;
}

标签:CF847E,int,题解,peo,cnt2,向右走,物品,Packmen,pack
来源: https://www.cnblogs.com/KinuhataSaiai/p/15512161.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有