COCI 2016 - Burza

Author: Kevin Sheng

Official Analysis

Explanation

Initial Analysis

Let's first try to transform the terms of the game into something less arbitrary.

Since Stjepan can't backtrack because he marks all nodes he visits himself, he can only move down the tree, increasing his depth as he goes. Given this, we can make a series of observations:

  1. Daniel can effectively "cut off" an entire subtree by marking a node, because then Stjepan can't get through that one node. Note that this node has to be at a level deeper than Stjepan's current level.
  2. If we can't prevent Stjepan from reaching a node of depth kk (with the root being of depth 00), then the game cannot always end in at most kk moves.
  3. Since we've already "lost" if Stjepan reaches depth kk, we don't care about anything below depth kk. We can also remove any nodes that don't lead to a depth of at least kk. Note that we won't consider any of these irrelevant nodes from here.

From the first observation, we can see that an optimal strategy would be to mark at most one node at each depth (excluding the root).

Since marking a node of depth dd makes at least kd+1k - d + 1 nodes off-limit and we can mark nodes from depth 11 to kk, if k(k+1)2n\frac{k \cdot (k + 1)}{2} \geq n, the game can always end in kk moves.

That reduces the maximum value of kk we have to consider down to around 30, which unfortunately is still too large for an exponential time solution. But it is something! Let's see if we can cut the bounds down further: 20 would be a good breakpoint.

Further Analysis

To limit the maximum number of steps to a point where bitwise DP is feasible, we have to prove that a game can always end in kk moves if k2nk^2 \geq n.

Since each move results in breaking a tree down into a bunch of smaller trees, we can do a proof by induction.

Let's define nrn_r as the total number of nodes that haven't been made invalid yet after rr moves, and trt_r as the number of valid nodes Stjepan can move to after rr moves (aka the number of valid nodes of depth r+1r+1).

For example, let's say that we were at a depth of 1 in the following tree: fork

If we cut off node 2, n1n_1 would be 3 and t1t_1 would be 1, since Stjepan can only move to node 3.

Our base case for the induction is the following:

nr(kr)2n_r \leq (k-r)^2

This is true for r=0r=0. Now, we just have to show that given the above,

nr+1(kr1)2=(kr)22r+2k1n_{r+1} \leq (k-r-1)^2 = (k-r)^2 - 2r + 2k - 1

If we show this, we'll know that nr(kr)2n_r \leq (k-r)^2 for all rr. Setting r=kr=k, we get nk(kk)2=0n_k \leq (k-k)^2=0, which effectively means that it's possible for us to make all nodes invalid after kk moves.

To prove this, let's first define a more concrete strategy:

At each level, cut off the node with the largest subtree size that hasn't been already cut off. If there's multiple nodes with this quality, cut off any of them.

If we follow the strategy defined earlier, at each turn we'll always cut off at least nrtr\frac{n_r}{t_r} nodes and also leave tr1t_r - 1 nodes behind, since they're now above our current depth. This yield the following inequality:

nr+1nrnrtr(tr1)n_{r+1} \leq n_r - \frac{n_r}{t_r} - (t_r - 1)

While this is a meaningful relationship, the trt_r terms are a bit nasty. It'd be great if we could just have a relation between nrn_r and nr+1n_{r+1}.

Fortunately, through algebraic manipulation, it is possible to obtain the following inequality:

nrnrtr(tr1)nr2nr+1n_r - \frac{n_r}{t_r} - (t_r - 1) \leq n_r - 2\sqrt{n_r} + 1

Chaining this with the above inequality, we get

nr+1nr2nr+1n_{r+1} \leq n_r - 2\sqrt{n_r} + 1

Since we know that nr(kr)2n_r \leq (k-r)^2 and by extension nrkr\sqrt{n_r} \leq k-r, we can substitute those terms to prove our desired expression:

nr+1(kr)22(kr)+1=(kr1)2n_{r+1} \leq (k-r)^2-2(k-r) + 1=(k-r-1)^2

And we're done! Since we've shown that any case where k2nk^2 \geq n will result in a win, we just have to handle the case where k<20k \lt 20, for which bitmask DP will suffice.

Bitmask DP

Note that since a tree is a planar graph, any node we cut off will cover a continuous segment of leaves.

Take the following tree as an example: tree

No node can cover only, say, 3 and 14. If it can cover those two then it also must cover node 1.

This leads us to our DP state. Let max_cover[S]\texttt{max\_cover}[S] be the maximum number of leaves we can cover from the start given we take one node from each depth specified in the subset.

For our transition, we try adding on depths to all previous subsets and iterate through all nodes in those depths.

For example, if removing a node could cover the third leaf to the fifth leaf and our current previous subset can cover up to the fourth leaf, then putting those two together yields a configuration that can cover up to the fifth leaf.

Implementation

Time Complexity: O(2nn)\mathcal{O}(2^{\sqrt{n}} \cdot n)

C++

#include <functional>
#include <iostream>
#include <map>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
int main() {

Join the USACO Forum!

Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!