-
Strange things
- WA took two hours
- Twice as fast as rk2, but the code is four times longer
- Please think about how to do this problem with dp
-
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
-
The number of steps is not enough to reach the leftmost item \ (\ to \) and return false directly
-
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
-
The number of steps is sufficient \ (\ to \) take the optimal solution in the two walking methods of 3 and 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; }