Cf847e packman problem solution

  • Strange things

  • meaning of the title

    Now there is a section where people and objects are on top of it, and sometimes there is space. People can move up left and right. Find the minimum of the maximum distance of people's movement when people's movement track covers all objects

  • Problem solution

    According to the meaning of the question, it is obviously two points. Consider another person's walking method:

    • Go left without looking back

    • Go right without looking back

    • Left and right, repeat on the left

    • Right, then left, repeat on the right

If we sweep people from left to right, we must make sure to walk the items on the left first, and walk to the right when there are still steps

This will WA on #7, because it may be better to go to the right first and then to the left to reach the first item that has not been reached, because there may be less repetition

Consider category discussion: use an item pointer to point to the leftmost item you haven't reached yet

  1. The number of steps is not enough to reach the leftmost item \ (\ to \) and return false directly

  2. The number of steps can only reach the leftmost item, and cannot go right \ (\ to \) update the item pointer to the right of the person

  3. The number of steps is sufficient \ (\ to \) take the optimal solution in the two walking methods of 3 and 4

  4. The pointer is on the right of the person \ (\ to \) update the object pointer to the right as much as possible

After completion, judge whether the pointer is greater than \ (CNT {package} \)

The reason is that the right boundary of the dichotomy should be \ (\ frac{3n}{2} \), that is, the answer that only one person is in the middle, first in a certain direction and then turn back. In the program, it is simply written as \ (2n \)

Final complexity: \ (O (CNT {people} \ log2n) \), significantly faster than \ (O(n\log2n) \)

  • code

#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)//First case
                return false;
            if (k <= peo[i] - pack[start_pos] + 1)//The second case
            {
                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])))
                {//In the third case, go left first
                    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])
                {//In the third case, go right first
                    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
        {//The fourth case
            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;//Pay attention to the dichotomy boundary
    while (L <= R)
    {
        int mid = (L + R) / 2;
        if (check(mid))
            R = mid - 1;
        else
            L = mid + 1;
    }
    cout << L;
}

Posted by desenhistas on Thu, 04 Nov 2021 19:03:14 -0700