USACO 2018 February: Snow Boots (Part 2)
USACO 2018 February: Snow Boots (Part 2)
Using a Monotone Deque!
Problem
It's winter on the farm, and that means snow! There are tiles on the path from the farmhouse to the barn, conveniently numbered , and tile is covered in feet of snow.
The next lines contain two space-separated integers each. The first integer on line is , the maximum depth of snow in which pair can step. The second integer on line is , the maximum step size for pair . It's guaranteed that and .
In his farmhouse cellar, Farmer John has pairs of boots, numbered . Some pairs are more heavy-duty than others, and some pairs are more agile than others. In particular, pair lets FJ step in snow at most feet deep, and lets FJ move at most forward in each step.
Farmer John starts off on tile and must reach tile to wake up the cows. Tile is sheltered by the farmhouse roof, and tile is sheltered by the barn roof, so neither of these tiles has any snow. Help Farmer John determine which pairs of snow boots will allow him to make the trek.
INPUT FORMAT (file snowboots.in):
The first line contains two space-separated integers and (The second line contains space-separated integers; the th integer is , the depth of snow on tile (). It's guaranteed that .The next lines contain two space-separated integers each. The first integer on line is , the maximum depth of snow in which pair can step. The second integer on line is , the maximum step size for pair . It's guaranteed that and .
OUTPUT FORMAT (file snowboots.out):
The output should consist of lines. Line should contain a single integer: if Farmer John can trek from tile to tile wearing the th pair of boots, and otherwise.SAMPLE INPUT:
8 7 0 3 8 5 6 9 0 0 0 5 0 6 6 2 8 1 10 1 5 3 150 7
SAMPLE OUTPUT:
0 1 1 0 1 1 1
Problem credits: Dhruv Rohatgi
How We Should Think Of It
Given an array of integers, find if there are more than Di consecutive numbers larger than Si. There are B (no greater than 100,000) values of Di and Si, and the array is no longer than 100,000 entries.
How To Solve It (Method 2)
This method is using a monotone stack.
Define a "barrier" as an entry OR an consecutive sequence of entries such that every entry in that sequence is greater than Si.
Let's try to force this problem into something searching for the first value smaller than a value.
Define L as an one-dimensional array. L[i] means, for the i-th element in the array, L[i] is the index of the first element that is smaller than the i-th element. Here, L[i] is on the left of i, and the first element means that its value will be as large as possible.
Define R as an one-dimensional array that's the exact opposite. R[i] means, for the i-th element in the array, R[i] is the index of the last element that is smaller than the i-th element. Here, R[i] is on the right of i, and the last element means that its value will be as large as possible.
This converts the problem into one in which the monotone stack can be used. It asks for the first such element that is smaller than a value (min monotone stack), and it asks for the last such value that is smaller than a value (min monotone stack but flipped array).
The length of the barrier would be L[i] - R[i] - 1, which we directly compare to Di to see if the "boot" can "step over".
We cannot use a queue because this problem requires us to add elements to the monotone "queue" from the front and remove elements from the monotone "queue" also from the front - LIFO, not FIFO.
We cannot use a queue because this problem requires us to add elements to the monotone "queue" from the front and remove elements from the monotone "queue" also from the front - LIFO, not FIFO.
Teacher's Code
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; const int maxN = 100000 + 10; const int maxB = 100000 + 10; struct a_t { int f, id; }a[maxN]; struct b_t { int s, d, id; }b[maxB]; int n, B, f[maxN], L[maxN], R[maxN]; int tail, queue[maxN]; bool ans[maxB]; void init() { scanf("%d%d", &n, &B); for (int i = 0; i < n; ++i) { scanf("%d", &a[i].f); a[i].id = i; } for (int i = 0; i < B; ++i) { scanf("%d%d", &b[i].s, &b[i].d); b[i].id = i; } } bool cmpF(a_t a, a_t b) { return a.f > b.f; } bool cmpS(b_t a, b_t b) { return a.s > b.s; } void solve() { tail = 0; queue[tail] = -1; for (int i = 0; i < n; ++i) { while (tail > 0 && a[i].f <= a[queue[tail]].f) --tail; L[i] = queue[tail]; queue[++tail] = i; } tail = 0; queue[tail] = n; for (int i = n-1; i >= 0; --i) { while (tail > 0 && a[i].f <= a[queue[tail]].f) --tail; R[i] = queue[tail]; queue[++tail] = i; } sort(a, a+n, cmpF); sort(b, b+B, cmpS); int next = 0, longest = 0; for (int i = 0; i < B; ++i) { int s = b[i].s; for (; next < n && a[next].f > s; ++next) { int id = a[next].id; longest = max(longest, R[id]-L[id]-1); } ans[b[i].id] = b[i].d > longest; } for (int i = 0; i < B; ++i) printf("%d\n", ans[i]); } int main() { for (int t = 1; t <= 10; ++t) { char name[256]; sprintf(name, "%d.in", t); freopen(name, "r", stdin); sprintf(name, "%d.ans", t); freopen(name, "w", stdout); init(); solve(); } return 0; }
My Code
#include <stack>
#include <fstream>
#include <algorithm>
#define MAXN 100005
using namespace std;
ifstream cin("snowboots.in");
ofstream cout("snowboots.out");
struct boot
{
int s, d, i;
constexpr bool operator<(const boot other) const
{
return s > other.s;
}
} boots[MAXN];
struct tile
{
int s, i;
constexpr bool operator<(const tile other) const
{
return s > other.s;
}
} path[MAXN];
stack<int> moq;
int N, B, ans[MAXN], R[MAXN], L[MAXN];
void read()
{
cin >> N >> B;
for(int i=0; i<N; i++) { cin >> path[i].s; path[i].i = i; }
for(int i=0; i<B; i++)
{
cin >> boots[i].s >> boots[i].d;
boots[i].i = i;
}
}
void solve()
{
moq.push(-1);
for(int i=0; i<N; i++)
{
while (moq.size() > 1 && path[i].s <= path[moq.top()].s) moq.pop();
L[i] = moq.top();
moq.push(i);
}
moq = { };
moq.push(N);
for(int i=N-1; i>=0; i--)
{
while (moq.size() > 1 && path[i].s <= path[moq.top()].s) moq.pop();
R[i] = moq.top();
moq.push(i);
}
sort(boots, boots + B);
sort(path, path + N);
int A = 0, barrier = 0;
for(int i=0; i<B; i++)
{
for (; A<N && path[A].s>boots[i].s; A++)
barrier = max(barrier, R[path[A].i]-L[path[A].i]-1);
ans[boots[i].i] = boots[i].d > barrier;
}
for(int i=0; i<B; i++) cout << ans[i] << endl;
}
int main()
{
read();
solve();
}
Comments
Post a Comment