### dragoon's blog

By dragoon, history, 3 years ago, Let's discuss the solutions.

How to solve B?   Comments (52)
 » How to solve H?
•  » » 3 years ago, # ^ | ← Rev. 2 →   The key idea is to solve the problem without the strings "A" and then iterate over the number of them to glue to words ending with 'S'.And that subproblem is just some tedious case-handling:"..SA" + "D..": connect min($cnt_{SA}$, $cnt_{D}$) words to each other and subtract 1 if the set of indices of words ending with "SA" is equal to the set of indices of words starting with "D" (they got connected into a cycle). Same for "..S" + "AD..".And the only case left is when all words got connected into one cycle. Subtract 1 more if all possible connections are made, union of sets "D.." and "AD.." is equal to union of sets "..S" and "..SA" and there were no subtractions in previous connections.
•  » » Copy-paste from recent JAG contest.
•  » » » :(
 » How to solve E?
•  » » 3 years ago, # ^ | ← Rev. 3 →   Let's emulate the specified in the statements algorithm, but instead of removing overlapped boxes on step 2, we will just skip this step and then for every processed box we will first check whether it was removed previously or not. If it "was removed" just skip it, otherwise select it.So we need to maintain some structure that allows adding new selected boxes and checking whether the current box overlaps enough with previously added boxes.Let's divide all the plane into square cells with side equal to $S$ and store these cells in the unordered map, i.e. for each non-empty cell we will store a vector of selected boxes inside this cell. Then to check if current box is overlapped with some other, we just need to go over 9 neighboring cells and calculate IOU with all boxes in those cells straightforwardly. The key idea is that there will be not too many boxes inside one cell because every pair of selected boxes should have $IOU <= threshold$.It passed in 1.2 out of 10 sec.
•  » » » Thanks!)
 » How to solve K, L?
 » 3 years ago, # | ← Rev. 2 →   We upsolved B like this: lets fix set of vertices. Initially it is only 0 in the set. Than make our moves find minimum digit that is adjacent to vertices of our set. Create new set with vertices that is adjacent to previous set by edges with minimum digit. Clearly this is best way we can go. Just save sets to some map and if your current set is equall to some previous set => you have cycle or if you have 1 in you current set => you have way withot cycles. Of course initially we remove vertices that can't be reached from 1 by reversed edges. By the way I don't know why it is not TL.
•  » » I think I can make a case where this TLs :) Create a few loops of zeros with coprime lengths, and add zero edges from 0 to one vertex in each loop, and one edges from one vertex in each loop to 1.
•  » » » Thanks, now I see
 » 3 years ago, # | ← Rev. 2 →   Can anyone please link a pdf of the problem-set?
•  » »
 » 3 years ago, # | ← Rev. 4 →   B: We didn't have time to implement but I think the following should work:1) Remove all vertices that don't have path to 1(bfs/dfs)2) Add edge 1->1 by number 03) From each vertex choose only edges with minimal digits4) Sort (in at most n iteration, each iteration O(n log n) or O(n) if counting sort) vertices by distance to 1: First, each vertex is in group by its outgoing digits. Then in each iteration vertex i is less the vertex j iff i was less than j on previous iteration or if they were equal and now min(class[outgoing[i]]) < min(class[outgoing[j]).5) Choose path from 0 greedily. You'll get some preperiod and period which you need to convert to A/B
•  » » 3 years ago, # ^ | ← Rev. 3 →   Sounds too complicated Remove all edges going to vertices having no path to 2. Maintain the set of vertices you can be at aftet going through $k$ edges. It's easy to recalculate the set for $k+1$ in O(V+E), just consider all minimal edges and go through them. Build the set for $k=V+eps$, if you notice during the computation that vertex 2 is in your set at some point, restore the path and break. Otherwise the answer is cyclic. Restore path for any vertex in set with $k=V+eps$, and find preperiod and period there.
•  » » » 3 years ago, # ^ | ← Rev. 2 →   I didn't understand. What is V+eps?
•  » » » » Number of edges to go through. If you go at least $V+1$ edges you will surely find the cycle, which is what we want to.
•  » » » Ok, that's indeed somewhat easier, thanks
 » We tried solving B by keeping a set of vertices and iteratively advance with the lowest digit edge (only considering vertices that reach $1$). We do this iteration $4n$ times, and then extrapolate the rational resulting number. However, it gives WA 7. Any ideas why?Code
•  » » Integer overflow at Out function. My solution is the same as you, but I iterated $3n+50$ times.
•  » » » Great, thanks...
•  » » I did the same bug, but I fixed it during contest :)
 » How to solve C?
•  » » 3 years ago, # ^ | ← Rev. 2 →   $dp[i][j]$ — the minimum price to put $i$ letters and have latest $j$ letters copied. $j = 0$ means the last move was to put a single letter.From any state $dp[i][j]$ you can put a single letter and go to $dp[i + 1]$, paste the current copied string into its next occurence and go to $dp[nxt[i][j]][j]$ (filling the rest of letters by single insertions) or copy the next $k$ letters from somewhere earlier (if there was such an occurence), paste it immediately and go to $dp[i + k][k]$.$nxt$ and occurrence checks can obviously be precomputed with z-function.
•  » » » 3 years ago, # ^ | ← Rev. 2 →   I think TL on C was absurdly tight. We had simple $O(n^2)$ DP solution with substring hashes computed with suffix arrays, but it gets TLE verdict (due to cache-friendliness issues).Code: https://pastebin.com/JPLWrVyS Lines 147-177 is the actual DP
•  » » » We got TLE with exactly this approach, could you share your code?
•  » » » » 3 years ago, # ^ | ← Rev. 3 →   works in 7.5 secondscode
 » How to solve I?
•  » » It works for all $n$. Just build a staircase: [(1, 1)] [(1, 2) (2, 2)] [(1, 3) (2, 3) (3, 3)] [(1, 4) (2, 4) (3, 4) (4, 4)] ... (i, j) means, you place block of $(i, j)$, with $j$ in the opposite side of sight.
 » Unfortunately, H was in recent MW camp, I think that's why it was solved so much.
 » 3 years ago, # | ← Rev. 2 →   Any fast solution for K? I solved it using small-to-large in 1.973s, I assume it was not intended.
•  » » My solution works in 0.879s. I think it was intended O(N log N) with small-to-large.
•  » » » My small-to-large solution is $O(N \log^2{N})$. How one can achieve $O(N \log{N})$?
•  » » » » For every component you can maintain number of numbers such that x and x+1 are in that component, answer for that component is size — that number. Question is how to avoid using sets. Well, you can have vectors and then when you are moving x from smaller vector to larger one, first you need to check if x+1 is there. Same for x-1. Code#include using namespace std; typedef long long ll; typedef double lf; typedef long double Lf; typedef pair pii; typedef pair pll; #define TRACE(x) cerr << #x << " " << x << endl #define FOR(i, a, b) for (int i = (a); i < int(b); i++) #define REP(i, n) FOR(i, 0, n) #define all(x) (x).begin(), (x).end() #define _ << " " << #define fi first #define sec second #define mp make_pair #define pb push_back const int MAXN = 200100; struct UnionFind { vector v[MAXN]; int connected[MAXN]; int par[MAXN]; void init() { REP(i, MAXN) { v[i].clear(); par[i] = i; connected[i] = 0; v[i].pb(i); } } void merge(int a, int b) { a = par[a]; b = par[b]; if ((int)v[a].size() < (int)v[b].size()) swap(a, b); for (auto x : v[b]) { if (par[x - 1] == a) connected[a]++; if (par[x + 1] == a) connected[a]++; v[a].pb(x); } for (auto x : v[b]) par[x] = a; connected[a] += connected[b]; } int get(int x) { x = par[x]; return (int)v[x].size() - connected[x]; } }; UnionFind Uf; int n, ans[MAXN]; vector v[MAXN]; void dfs(int node, int par) { for (auto nnode : v[node]) { if (nnode == par) continue; dfs(nnode, node); Uf.merge(node, nnode); } ans[node] = Uf.get(node); } void solve(int test) { scanf("%d",&n); Uf.init(); REP(i, MAXN) v[i].clear(); REP(i, n - 1) { int a, b; scanf("%d %d",&a,&b); v[a].pb(b); v[b].pb(a); } dfs(1, -1); printf("Case #%d: ", test); FOR(i, 1, n + 1) printf("%d ",ans[i]); puts(""); } int main() { int t; cin >> t; REP(i, t) solve(i + 1); return 0; } 
•  » » 3 years ago, # ^ | ← Rev. 2 →   We have just LCA + DSU that passes in 1 second. I guess you can make it sub-nlogn but idk if that will be faster :)
•  » » » Could you please elaborate your solution in detail?
•  » » » » Well, it's just that $i$ and $i + 1$ merge their segments at $lca(i, i + 1)$. With this fact you simply collect all the updates you'll need to do in each vertex and do one dfs. The answer for vertex $v$ is $1 + \sum \limits_{u \in g_v} ans_u$ minus the number of updates in $v$.Also I just realized I don't even use dsu here.
 » What about J? Is this test valid? 2 message A { required A name1 = 1; required string name2 = 100; } message B { required B name1 = 1; required string name2 = 101; } 1 A B At least, there is no such case in testset, but I think I didn't found anything against it in statement. Answer formally is compatible. Also, what's the reason of giving 6-page statement with about 10% useful information?
•  » » We didn't find anything about it, either, so we assumed this stuff can happen (and I just checked that the protobuf compiler consumes this description just fine). I don't know if I'm more relieved or surprised that such a case was not in the testset. :P
 » What's a reliable way to ask for clarifications during the OpenCups? We asked a couple of clarifying questions through the Yandex system within 2h of the start of the contest and we never got a response. :(
•  » » I thought that asking Snark in Telegram was most reliable, but that also didn't work today.
 » BTW are the authors of this contest known? I saw at least three problems that made me interested by the context :)
 » How to solve G?
•  » » 3 years ago, # ^ | ← Rev. 3 →   Let $v_1, v_2, \ldots, v_k$ be the sons of the root. Let $l_i$ be the depth of the deepest taken vertex in the subtree of $v_i$ (possibly $l_i = 0$). It turns out that the second player wins if and only if $max(l_1, \ldots, l_k) = max_2(l_1, \ldots, l_k)$. It can be proved using the fact that we can remove all vertices which are ends of some diameter (at least I thought this proof is correct during the contest). Implementation is pretty standard, complexity is $O(n \cdot log(n))$.
•  » » » Could you clarify the implementation? In my code I had to divide by numbers that could be zero modulo 10**9+7, but luckily there were no such testcases.
•  » » » » 3 years ago, # ^ | ← Rev. 5 →   I do it too, but I think its easy not to do it. When I maintain these arrays $arr_{v, j}$ — how many ways to choose in the subtree of $v$ vertices with the deepest one in the depth $j$, I need to multiply some suffix by $x$, so I divide some prefix by $x$, but I can just not to do it if $x = 0$, adding some parameter "what suffix is turned to $0$", recalculating this after every action with the array.When I calculate the answer, I can do it too, storing the number of ways in the subtrees which cant provide another depth $d$ separately and using prefix sums for others.
•  » » » » » Right, that should work!
 » Can someone explain how to solve problem L?
•  » » Code brute -> notice the pattern.
•  » » 3 years ago, # ^ | ← Rev. 3 →   Print 2 when n or m is 1, else 2n + 2m — 4.
•  » » » can you explain whay answer is 8 + 2 * (a — 3 + b -3 ) for a > 2 and b > 2