tag:blogger.com,1999:blog-48164323432163705502024-02-26T05:13:08.062+08:00a bit of csan exploration on computer science and mathematicsPrajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.comBlogger249125tag:blogger.com,1999:blog-4816432343216370550.post-28802817953452428332020-11-15T14:43:00.001+08:002020-11-15T14:43:27.749+08:00in-place merge sort (sort of)So I just saw this discussion <a href="https://stackoverflow.com/questions/2571049/how-to-sort-in-place-using-the-merge-sort-algorithm">https://stackoverflow.com/questions/2571049/how-to-sort-in-place-using-the-merge-sort-algorithm</a> and I think the top-voted answer is brilliant. Felt like I have found a rare gem and want to share it to the rest of the world.<div><br /></div><div>The problem statement is: "How do you perform in-place merge sort?".</div><div><br /></div><div><i>In-place</i> more or less means requiring O(1) extra space. However, in this post, I'm going to describe a variant which requires O(log N) extra space and takes O(N log^2 N) to run, since the final algorithm will still be using recursions. I think it's a good trade-off, since it still highlights the main ideas and the code is still simple.</div><div><br /></div><div>We'll arrive at the algorithm by a series of false starts.</div><div><br /></div><div>Let's start with the ordinary merge sort:</div><div><br /></div><div><i>sort(A[], i, j):</i></div><div><i> m = (i + j) / 2</i></div><div><i> sort(A[], i, m)</i></div><div><i> sort(A[], m+1, j)</i></div><div><i> merge(A[], i, m, m+1, j)</i></div><div><br /></div><div>Or in plain English: to sort, you sort the first half, then sort the second half, and then merge the two sorted list into one sorted list.</div><div><br /></div><div>The <i>merge</i> operation is very simple, just like merging 2 sorted decks of cards: repeatedly take one from the top of each pile, then place the smaller one on the third pile.</div><div><br /></div><div>This "third" pile is usually represented as a temporary array, large enough to hold the result of the merge, which means O(N) extra space.</div><div><br /></div><div>Here comes the challenge: Can we do better than this in terms of extra space required?</div><div><br /></div><div>If you have never thought of this problem before, I recommend you thinking about it a little bit (or a lot) before I spoil it to you.</div><div><br /></div><div><br /></div><div>OK.</div><div><br /></div><div><br /></div><div>The first thing that we may try to do is to right away try to merge the two sorted halves. That's pretty hard.</div><div><br /></div><div>So there comes the brilliant idea #1 from the Stack Overflow answer: what if we leave some unsorted regions which we can use to store our temporary merge operations?</div><div><br /></div><div>For example, say we now only aim to sort half of the array, leaving the other half unsorted:</div><div>[ <------ 1/2 unsorted -------> | <------- 1/2 to be sorted -------> ]</div><div><br /></div><div>Then we can use the unsorted region to store our merge operation by swapping sorted items with unsorted items.</div><div><br /></div><div>Here's an illustration:</div><div><span style="font-family: courier;">2 5 | 1 4 | A B C D |</span></div><div><br /></div><div>[A, B, C, D] is the unsorted items, while [2, 5] and [1, 4] are the sorted lists to be merged. Then the merging operation, done step by step, will look as follows:</div><div><br /></div><div><span style="font-family: courier;"><b><span style="color: #2b00fe;">2</span></b> 5 | <b><span style="color: #800180;">1</span></b> 4 | </span><span style="font-family: courier;"><b><span style="color: red;">A</span></b> B C D | // swap A and 1.</span></div><div><span style="font-family: courier;"><b><span style="color: #2b00fe;">^</span> <span style="color: #800180;">^</span> <span style="color: red;">^</span></b></span></div><div><span style="font-family: courier;"><b><span style="color: #2b00fe;">2</span></b> 5 | A <b><span style="color: #800180;">4</span></b> | </span><span style="font-family: courier;">1 <b><span style="color: red;">B</span></b> C D |</span><span style="font-family: courier;"> // swap B and 2</span></div><div><span style="font-family: courier;"><b><span style="color: #2b00fe;">^</span> <span style="color: #800180;">^</span> <span style="color: red;">^</span></b></span></div><div><span style="font-family: courier;">B <b><span style="color: #2b00fe;">5</span></b> | A <b><span style="color: #800180;">4</span></b> | 1 2 <b><span style="color: red;">C</span></b> D | // swap C and 4</span></div><div><span style="font-family: courier;"> <b> <span style="color: #2b00fe;">^</span> <span style="color: #800180;"> ^</span> <span style="color: red;">^</span></b></span></div><div><span style="font-family: courier;">B<b> <span style="color: #2b00fe;">5</span></b> | A C <span style="color: #800180;">|</span> 1 2 4 <b><span style="color: red;">D</span></b> | // swap D and 5</span></div><div><span style="font-family: courier;"> <b> <span style="color: #2b00fe;">^</span></b> <span style="color: #800180;">^</span> <b> <span style="color: red;">^</span></b></span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;">B D</span> <span style="color: #2b00fe;">|</span> <span style="color: #800180;">A C |</span> <span style="color: red;">1 2 4 5 | </span>// Done</span></div><div><span style="font-family: courier;"> <span style="color: #2b00fe;">^</span> <span style="color: #800180;">^</span> <span style="color: red;">^</span></span></div><div><br /></div><div>We end up with [B, D, A, C] unsorted on the left side, and [1, 2, 4, 5] sorted on the right side.</div><div><br /></div><div>With this idea alone, you would be able to sort half of the array. What about the other half of the array? Well, we can do the same too! So schematically it will look like this:</div><div>[ <--- 1/4 unsorted ----> | <---- 1/4 sorted ---> | <--- 1/2 sorted ----> ]</div><div><br /></div><div>However at this point, what we want is to merge the 1/4 sorted and 1/2 sorted parts, but we only have 1/4 unsorted buffer which is clearly not enough to contain 1/4 + 1/2 = 3/4 of the items.</div><div><br /></div><div>Here comes brilliant idea #2, which I will call "in-place merging with empty slots".</div><div><br /></div><div>Say we 2 sorted lists of size M and N. For example, say M = 3 and N = 5, as shown in the following illustration:</div><div><br /></div><div><span style="font-family: courier;">2 4 7 | A B C 1 3 5 6 9 |</span></div><div><span style="font-family: courier;"><br /></span></div><div><span style="font-family: inherit;">Here, [2, 4, 7] is a sorted list of size M = 3, and [1, 3, 5, 6, 9] is a sorted of size N = 5. </span></div><div><span style="font-family: inherit;">A, B, C are the empty slots, since M = 3, there are 3 of them. We name them A, B, C just to help keeping track of them. In reality, we don't care they order of the empty slots.</span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;">How shall we proceed in merging them? Follow this and you will get it:</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>3</b></span> 6 7 | <span style="color: #800180;"><b>A</b></span> <span style="color: #800180;">B C</span> <span style="color: red;"><b>1</b></span> 2 5 8 9 | // swap A and 1</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>3</b></span> 6 7 | 1 <span style="color: #800180;"><b>B</b></span> <span style="color: #800180;">C A</span> <span style="color: red;"><b>2</b></span> 5 8 9 | // swap B and 2</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>3</b></span> 6 7 | 1 2<b> <span style="color: #800180;">C</span></b> <span style="color: #800180;">A B</span> <span style="color: red;"><b>5</b></span> 8 9 | // swap C and 3</span></div><div><span style="font-family: courier;"><span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;">C <span style="color: #2b00fe;"><b>6</b></span> 7 | 1 2 3 <span style="color: #800180;"><b>A</b></span> <span style="color: #800180;">B</span> <span style="color: red;"><b>5</b></span> 8 9 | // swap A and 5</span></div><div><span style="font-family: courier;"> <span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;">C <span style="color: #2b00fe;"><b>6</b></span> 7 | 1 2 3 5<b> <span style="color: #800180;">B</span></b> <span style="color: #800180;">A</span> <span style="color: red;"><b>8</b></span> 9 | // swap B and 6</span></div><div><span style="font-family: courier;"> <span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;">C B <span style="color: #2b00fe;"><b>7</b></span> | 1 2 3 5 6 <span style="color: #800180;"><b>A</b></span> <span style="color: red;"><b>8</b></span> 9 | // swap A and 7</span></div><div><span style="font-family: courier;"> <span style="color: #2b00fe;"><b>^</b></span> <span style="color: #800180;"><b>^</b></span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;">C B A <span style="color: #2b00fe;">|</span> 1 2 3 5 6 7 <span style="color: red;"><b>8</b></span> 9 | // Done (kind of)</span></div><div><span style="font-family: courier;"> <span style="color: #2b00fe;">^</span> <span style="color: red;"><b>^</b></span></span></div><div><span style="font-family: courier;"> <span style="color: #800180;"><b>^</b></span></span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;">It might be harder to understand because the empty slots are intermixed with the sorted list. However it has very intuitive feel to it. As the merging process goes on, the empty slots "bubble up" and one by one they "pop".</span></div><div><span style="font-family: inherit;"><br /></span></div><div><span style="font-family: inherit;">Now, how would we apply this idea to the previous problem of merging 1/4 sorted list to 1/2 sorted list? Here's how. What if we re-arrange the order we do things, and instead end up with the 1/4 unsorted array in between them, as follows:</span></div><div>[ <--- 1/4 sorted ----> | <-- 1/4 unsorted --> | <----------------- 1/2 sorted --------------->]</div><div><br /></div><div>Then we can pretend that the 1/4 unsorted items are "empty slots" which will bubble up and get popped with the items in the 1/4 sorted array, using our "in-place merging with empty slots" demonstrated above!</div><div><br /></div><div>We'll then end up with the following:</div><div>[ <--- 1/4 unsorted ---> | <---------------------- 3/4 sorted ------------------------> ]</div><div><br /></div><div>We can then repeat the process on the 1/4 unsorted to get 1/8 sorted, 1/8 unsorted, 3/4 sorted, then perform the "in-place merging with empty slots", and so on until we have 1/8, 1/16, 1/32 unsorted region and so on.</div><div><br /></div><div>When will this end? It ends when the unsorted region is small enough, e.g. < 10 elements, where we can simply perform an insertion sort on the entire array once, which will be of the order O(N) since insertion sort is linear on "almost sorted" arrays.</div><div><br /></div><div>Here's the code (disclaimer: might be wrong)</div>
<!--HTML generated using hilite.me--><div style="background: rgb(255, 255, 255); border-color: gray; border-image: initial; border-style: solid; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;"><table><tbody><tr><td><pre style="line-height: 125%; margin: 0px;"> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48</pre></td><td><pre style="line-height: 125%; margin: 0px;"><span style="color: #557799;">#include <stdio.h></span>
<span style="color: #557799;">#define N 1000000</span>
<span style="color: #333399; font-weight: bold;">int</span> a[N];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">swap</span>(<span style="color: #333399; font-weight: bold;">int</span> i,<span style="color: #333399; font-weight: bold;">int</span> j){
<span style="color: #333399; font-weight: bold;">int</span> c<span style="color: #333333;">=</span>a[i];
a[i]<span style="color: #333333;">=</span>a[j];
a[j]<span style="color: #333333;">=</span>c;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">merge</span>(<span style="color: #333399; font-weight: bold;">int</span> a[],<span style="color: #333399; font-weight: bold;">int</span> x,<span style="color: #333399; font-weight: bold;">int</span> y,<span style="color: #333399; font-weight: bold;">int</span> m,<span style="color: #333399; font-weight: bold;">int</span> n,<span style="color: #333399; font-weight: bold;">int</span> w) {
<span style="color: #008800; font-weight: bold;">while</span>(x<span style="color: #333333;"><=</span>y<span style="color: #333333;">&&</span>m<span style="color: #333333;"><=</span>n){
swap(w<span style="color: #333333;">++</span>,a[x]<span style="color: #333333;"><</span>a[m]<span style="color: #333333;">?</span>x<span style="color: #333333;">++:</span>m<span style="color: #333333;">++</span>);
}
<span style="color: #008800; font-weight: bold;">while</span>(x<span style="color: #333333;"><=</span>y){
swap(w<span style="color: #333333;">++</span>,x<span style="color: #333333;">++</span>);
}
<span style="color: #008800; font-weight: bold;">while</span>(m<span style="color: #333333;"><=</span>n){
swap(w<span style="color: #333333;">++</span>,m<span style="color: #333333;">++</span>);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">insertion_sort</span>(<span style="color: #333399; font-weight: bold;">int</span> a[],<span style="color: #333399; font-weight: bold;">int</span> i,<span style="color: #333399; font-weight: bold;">int</span> j){
<span style="color: #333399; font-weight: bold;">int</span> m,n;
<span style="color: #008800; font-weight: bold;">for</span>(m<span style="color: #333333;">=</span>i;m<span style="color: #333333;"><=</span>j;<span style="color: #333333;">++</span>m){
<span style="color: #008800; font-weight: bold;">for</span>(n<span style="color: #333333;">=</span>m;n<span style="color: #333333;">></span>i<span style="color: #333333;">&&</span>a[n]<span style="color: #333333;"><</span>a[n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>];<span style="color: #333333;">--</span>n){
swap(n,n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">sort</span>(<span style="color: #333399; font-weight: bold;">int</span> a[],<span style="color: #333399; font-weight: bold;">int</span> i,<span style="color: #333399; font-weight: bold;">int</span> j) {
<span style="color: #333399; font-weight: bold;">int</span> m<span style="color: #333333;">=</span>j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>,n<span style="color: #333333;">=</span>j,w,x;
<span style="color: #008800; font-weight: bold;">while</span>(j<span style="color: #333333;">-</span>i<span style="color: #333333;">></span><span style="color: #0000dd; font-weight: bold;">1</span>){
x<span style="color: #333333;">=</span>(i<span style="color: #333333;">+</span>j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
w<span style="color: #333333;">=</span>(i<span style="color: #333333;">+</span>j)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
sort(a,i,x);
merge(a,i,x,m,n,w);
m<span style="color: #333333;">=</span>w;
j<span style="color: #333333;">=</span>w<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
insertion_sort(a,i,n);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>() {
<span style="color: #333399; font-weight: bold;">int</span> n,i;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
<span style="color: #008800; font-weight: bold;">for</span>(i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i)scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a[i]);
sort(a,<span style="color: #0000dd; font-weight: bold;">0</span>,n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,n);
<span style="color: #008800; font-weight: bold;">for</span>(i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i)printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,a[i]);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre></td></tr></tbody></table></div><div><br /></div><div>Now, analysis.</div><div><br /></div><div>Extra space?</div><div>Well, extra space needed is O(log N) since the implementation still does a recursion, which requires stack to keep track of the recursion, and the recursion can only go O(log N) deep. </div><div><br /></div><div>Run-time complexity?</div><div>More difficult to see. First of all, the merge operation is O(N). What about sort? Let T(n) be the run-time complexity of sort. Then T(n) = sum of [O(n) + T(k)] for k = n/2, n/4, n/8, ... </div><div>Since we call merge only at most O(log n) times, the merge operations take overall O(n log n) time.</div><div>So it reduces to T(n) = O(n log n) + T(n/2) + T(n/4) + T(n/8) + ...</div><div>Which reduces to T(n) = O(n log n) + 2 T(n/2), which reduces to T(n) = O(n log^2 n).</div><div><br /></div><div>Are you not happy with the fact that this runs slower than O(N log N) merge sort? Then here's a challenge for you: How would you improve the above implementation so that it really runs in O(N log N) time? Hint: we haven't exploited brilliant idea #1 in the code yet. Enjoy!</div>Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-22680858221764660992019-06-02T17:23:00.001+08:002019-06-02T17:23:38.212+08:00Merging heaps in O(log N)?Can you merge two heaps in O(log N)? Turns out if they are leftist heaps, you can!<br />
But what is a leftist heap, and how is it different from binary heap?<br />
<br />
Recall that binary heap is both complete and balanced. Hence it looks something like this:<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">1</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">2</span> <span style="color: #008c00;">3</span>
<span style="color: #808030;">/</span> \ <span style="color: #808030;">/</span>
<span style="color: #008c00;">5</span> <span style="color: #008c00;">6</span> <span style="color: #008c00;">7</span>
Fig <span style="color: #008c00;">1</span>
</pre>
It's clear that it supports O(log N) operations.<br />
<br />
In contrast, this is what leftist heap looks like:<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">1</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">3</span> <span style="color: #008c00;">2</span>
<span style="color: #808030;">/</span> <span style="color: #808030;">/</span>
<span style="color: #008c00;">5</span> <span style="color: #008c00;">7</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">6</span>
Fig <span style="color: #008c00;">2</span>
</pre>
It's neither complete nor balanced. Yet, it supports O(log N) operations too!<br />
<br />
How does it work?<br />
<br />
<a name='more'></a><br />
<h3>
<span style="font-size: large;"><b>Idea behind Leftist Heap</b></span></h3>
<br />
Each node on a leftist heap has a 'rank'. It is defined as the shortest distance to its empty child. Hence in the example tree above (Fig 2), the rank of node '1' is 2, while the rank of node '3' is 1. By definition, the rank of an empty (NULL) node is 0.<br />
<br />
Each node maintains the following property:<br />
1. value of current node is smaller than those of its children (the usual min-heap property)<br />
2. the rank of its left child is greater than or equal to the rank of its right child (the leftist property!)<br />
<br />
The leftist property has a consequence: the rank of a node is = 1 + the rank of its right child. Do you see it?<br />
<br />
So, how does the leftist property help us support O(log N) insertion and deletion operations? Introducing, the "merge" operation!<br />
<br />
<h3>
<span style="font-size: large;"><b>Merging Leftist Heap</b></span></h3>
<br />
As it turns out, we can merge 2 leftist heap efficiently:<br />
1. First we compare the min values of the leftist heaps. Let's call the one with a smaller min value as A, and the other as B.<br />
2. We recursively merge B with the right child of A, call the result M.<br />
3. Then we attach M as the new right child of A.<br />
4. Wait, what if M has a larger rank than the left child of A? Well, we simply swap them! Hence, we maintain leftist property of heap A as such.<br />
<br />
Here is an illustration:<br />
<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">1</span> MERGE WITH <span style="color: #008c00;">4</span>
<span style="color: #808030;">/</span> \ <span style="color: #808030;">/</span> \
<span style="color: #008c00;">3</span> <span style="color: #008c00;">2</span> <span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span> <span style="color: #808030;">/</span> <span style="color: #808030;">/</span>
<span style="color: #008c00;">5</span> <span style="color: #008c00;">7</span> <span style="color: #008c00;">12</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">6</span>
A B
</pre>
<pre style="background: #ffffff; color: black;"></pre>
Here we merge B to the right child of A. Let's focus on those:<br />
<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">2</span> MERGE WITH <span style="color: #008c00;">4</span>
<span style="color: #808030;">/</span> <span style="color: #808030;">/</span> \
<span style="color: #008c00;">7</span> <span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">12</span>
</pre>
<pre style="background: #ffffff; color: black;"><span style="color: #008c00;">
</span></pre>
In this case, we merge heap '4' with right child of '2'. Since the right child is<br />
empty, we simply attach '4' to it:<br />
<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">2</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">7</span> <span style="color: #008c00;">4</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">12</span>
</pre>
<pre style="background: #ffffff; color: black;"><span style="color: #008c00;">
</span></pre>
But since the left child of '2' has a rank of 1 while its right child has a rank of 2, we must swap the children:<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">2</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">4</span> <span style="color: #008c00;">7</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">12</span>
M
</pre>
Next we attach this to the right child of the original heap A:<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">1</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">3</span> <span style="color: #008c00;">2</span>
<span style="color: #808030;">/</span> <span style="color: #808030;">/</span> \
<span style="color: #008c00;">5</span> <span style="color: #008c00;">4</span> <span style="color: #008c00;">7</span>
<span style="color: #808030;">/</span> <span style="color: #808030;">/</span> \
<span style="color: #008c00;">6</span> <span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">12</span>
</pre>
Finally, since the left child of '1' has rank 1 while its right child has rank 2, we must do a final swap and we get the result of the merge as:<br />
<br />
<pre style="background: #ffffff; color: black;"> <span style="color: #008c00;">1</span>
<span style="color: #808030;">/</span> \
<span style="color: #008c00;">2</span> <span style="color: #008c00;">3</span>
<span style="color: #808030;">/</span> \ <span style="color: #808030;">/</span>
<span style="color: #008c00;">4</span> <span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span>
<span style="color: #808030;">/</span> \ <span style="color: #808030;">/</span>
<span style="color: #008c00;">7</span> <span style="color: #008c00;">5</span> <span style="color: #008c00;">6</span>
<span style="color: #808030;">/</span>
<span style="color: #008c00;">12</span>
</pre>
<br />
The time complexity of merge operation is O(rank of heap). (Here, rank of heap is the rank of its root node)<br />
<br />
But, what is the upper bound of the rank, in relation to the size of the tree? It turns out, for a leftist heap with rank R, the number of nodes in the heap is at least \(2^R-1\). This means \(2^R-1\) <= N or R <= log (N+1), or R = O(log N).<br />
<br />
Proof:
By induction on S(R) = minimum size of leftist heap with rank R.<br />
Base case: S(1). The smallest possible such leftist heap is a leaf node, hence S(1) = 1 = \(2^1 -1\).<br />
Inductive case: Say \(S(k) = 2^k-1\) for all k <= R. What is S(R+1)?<br />
Consider the right subtree of the root. This is a leftist heap with rank R. Hence smallest possible size for this subtree is S(R) = \(2^R-1\).<br />
How about the left subtree of the root? It can have rank >= R. The smallest possible size is therefore S(R) = \(2^R-1\) when the rank = R.<br />
Hence in total, S(R+1) must be \((2^R-1) + (2^R-1) + 1 = 2^{R+1}-1\), proving the inductive case.
<br />
<br />
Hence time complexity of merge operation is O(log N).<br />
<h3>
<span style="font-size: large;"><br /></span></h3>
<h3>
<span style="font-size: large;">Insertion and Deletion on Leftist Heap</span></h3>
<br />
Insertion can be done as merging the existing heap with a new heap with 1 node. Deletion of the root of a heap is done by merge its left and right children.<br />
<br />
Hence these operations are O(log N)!<br />
<br />
Here is the full implementation:<br />
<br />
<pre style="background: #ffffff; color: black;"><span style="color: #004a43;">#</span><span style="color: #004a43;">include </span><span style="color: maroon;"><</span><span style="color: #40015a;">cstdio</span><span style="color: maroon;">></span>
<span style="color: #004a43;">#</span><span style="color: #004a43;">include </span><span style="color: maroon;"><</span><span style="color: #40015a;">vector</span><span style="color: maroon;">></span>
<span style="color: #004a43;">#</span><span style="color: #004a43;">include </span><span style="color: maroon;"><</span><span style="color: #40015a;">cstdlib</span><span style="color: maroon;">></span>
<span style="color: #004a43;">#</span><span style="color: #004a43;">include </span><span style="color: maroon;"><</span><span style="color: #40015a;">queue</span><span style="color: maroon;">></span>
<span style="color: #004a43;">#</span><span style="color: #004a43;">include </span><span style="color: maroon;"><</span><span style="color: #40015a;">cassert</span><span style="color: maroon;">></span>
<span style="color: maroon; font-weight: bold;">using</span> <span style="color: maroon; font-weight: bold;">namespace</span> <span style="color: #666616;">std</span><span style="color: purple;">;</span>
<span style="color: dimgrey;">// NOTE: This is an implementation of leftist heap for educational purposes</span>
<span style="color: dimgrey;">// only. It does not deal with any memory management, and it pays 0 respect</span>
<span style="color: dimgrey;">// for software eng practices. Read and use at your own risk.</span>
<span style="color: dimgrey;">// Leftist heap node definition.</span>
<span style="color: maroon; font-weight: bold;">struct</span> Node <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">int</span> value<span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">int</span> rank<span style="color: purple;">;</span>
Node <span style="color: #808030;">*</span>left<span style="color: purple;">;</span>
Node <span style="color: #808030;">*</span>right<span style="color: purple;">;</span>
<span style="color: purple;">}</span><span style="color: purple;">;</span>
<span style="color: dimgrey;">// Private functions.</span>
Node <span style="color: #808030;">*</span>create_leaf_node<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> value<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: maroon; font-weight: bold;">new</span> Node<span style="color: purple;">{</span>value<span style="color: #808030;">,</span> <span style="color: #008c00;">1</span><span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">nullptr</span><span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">nullptr</span><span style="color: purple;">}</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">int</span> get_rank<span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>node<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span><span style="color: #808030;">!</span>node<span style="color: #808030;">)</span> <span style="color: maroon; font-weight: bold;">return</span> <span style="color: #008c00;">0</span><span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">return</span> node<span style="color: #808030;">-</span><span style="color: #808030;">></span>rank<span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">// Creates a new leftist heap.</span>
Node <span style="color: #808030;">*</span>create_node<span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> value<span style="color: #808030;">,</span> Node <span style="color: #808030;">*</span>heap_a<span style="color: #808030;">,</span> Node <span style="color: #808030;">*</span>heap_b<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>get_rank<span style="color: #808030;">(</span>heap_a<span style="color: #808030;">)</span> <span style="color: #808030;">></span><span style="color: #808030;">=</span> get_rank<span style="color: #808030;">(</span>heap_b<span style="color: #808030;">)</span><span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: maroon; font-weight: bold;">new</span> Node<span style="color: purple;">{</span>value<span style="color: #808030;">,</span> get_rank<span style="color: #808030;">(</span>heap_b<span style="color: #808030;">)</span><span style="color: #808030;">+</span><span style="color: #008c00;">1</span><span style="color: #808030;">,</span> heap_a<span style="color: #808030;">,</span> heap_b<span style="color: purple;">}</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: maroon; font-weight: bold;">new</span> Node<span style="color: purple;">{</span>value<span style="color: #808030;">,</span> get_rank<span style="color: #808030;">(</span>heap_a<span style="color: #808030;">)</span><span style="color: #808030;">+</span><span style="color: #008c00;">1</span><span style="color: #808030;">,</span> heap_b<span style="color: #808030;">,</span> heap_a<span style="color: purple;">}</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">// Merges leftist heap 'first' with 'second' and returns the pointer to the</span>
<span style="color: dimgrey;">// merged heap. Destroys both 'first' and 'second'.</span>
Node <span style="color: #808030;">*</span><span style="color: #603000;">merge</span><span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>first<span style="color: #808030;">,</span> Node <span style="color: #808030;">*</span>second<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span><span style="color: #808030;">!</span>first<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> second<span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span><span style="color: #808030;">!</span>second<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> first<span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span>first<span style="color: #808030;">-</span><span style="color: #808030;">></span>value <span style="color: #808030;">></span> second<span style="color: #808030;">-</span><span style="color: #808030;">></span>value<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #603000;">merge</span><span style="color: #808030;">(</span>second<span style="color: #808030;">,</span> first<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">return</span> create_node<span style="color: #808030;">(</span>first<span style="color: #808030;">-</span><span style="color: #808030;">></span>value<span style="color: #808030;">,</span> first<span style="color: #808030;">-</span><span style="color: #808030;">></span>left<span style="color: #808030;">,</span> <span style="color: #603000;">merge</span><span style="color: #808030;">(</span>first<span style="color: #808030;">-</span><span style="color: #808030;">></span>right<span style="color: #808030;">,</span> second<span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">// Debug interface.</span>
<span style="color: maroon; font-weight: bold;">void</span> print<span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>heap<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">if</span> <span style="color: #808030;">(</span><span style="color: #808030;">!</span>heap<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: #603000;">printf</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">E</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">return</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: #603000;">printf</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">(</span><span style="color: #007997;">%d</span><span style="color: #0000e6;">[</span><span style="color: #007997;">%d</span><span style="color: #0000e6;">]</span><span style="color: maroon;">"</span><span style="color: #808030;">,</span> heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>value<span style="color: #808030;">,</span> heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>rank<span style="color: #808030;">)</span><span style="color: purple;">;</span>
print<span style="color: #808030;">(</span>heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>left<span style="color: #808030;">)</span><span style="color: purple;">;</span>
print<span style="color: #808030;">(</span>heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>right<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: #603000;">printf</span><span style="color: #808030;">(</span><span style="color: maroon;">"</span><span style="color: #0000e6;">)</span><span style="color: maroon;">"</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: dimgrey;">// Public interfaces.</span>
Node <span style="color: #808030;">*</span>push<span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>heap<span style="color: #808030;">,</span> <span style="color: maroon; font-weight: bold;">int</span> value<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #603000;">merge</span><span style="color: #808030;">(</span>heap<span style="color: #808030;">,</span> create_leaf_node<span style="color: #808030;">(</span>value<span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">int</span> top<span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>heap<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>value<span style="color: purple;">;</span>
<span style="color: purple;">}</span>
Node <span style="color: #808030;">*</span>pop<span style="color: #808030;">(</span>Node <span style="color: #808030;">*</span>heap<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #603000;">merge</span><span style="color: #808030;">(</span>heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>left<span style="color: #808030;">,</span> heap<span style="color: #808030;">-</span><span style="color: #808030;">></span>right<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">int</span> <span style="color: #400000;">main</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">int</span> N <span style="color: #808030;">=</span> <span style="color: #008c00;">500000</span><span style="color: purple;">;</span>
Node <span style="color: #808030;">*</span>heap <span style="color: #808030;">=</span> <span style="color: maroon; font-weight: bold;">nullptr</span><span style="color: purple;">;</span>
<span style="color: #666616;">std</span><span style="color: purple;">::</span><span style="color: #603000;">priority_queue</span><span style="color: purple;"><</span><span style="color: maroon; font-weight: bold;">int</span><span style="color: purple;">></span> pq<span style="color: purple;">;</span>
<span style="color: maroon; font-weight: bold;">for</span> <span style="color: #808030;">(</span><span style="color: maroon; font-weight: bold;">int</span> i <span style="color: #808030;">=</span> <span style="color: #008c00;">0</span><span style="color: purple;">;</span> i <span style="color: #808030;"><</span> N<span style="color: purple;">;</span> <span style="color: #808030;">+</span><span style="color: #808030;">+</span>i<span style="color: #808030;">)</span> <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">int</span> v <span style="color: #808030;">=</span> <span style="color: #603000;">rand</span><span style="color: #808030;">(</span><span style="color: #808030;">)</span> <span style="color: #808030;">%</span> N<span style="color: purple;">;</span>
pq<span style="color: #808030;">.</span>push<span style="color: #808030;">(</span><span style="color: #808030;">-</span>v<span style="color: #808030;">)</span><span style="color: purple;">;</span>
heap <span style="color: #808030;">=</span> push<span style="color: #808030;">(</span>heap<span style="color: #808030;">,</span> v<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">while</span> <span style="color: #808030;">(</span>N<span style="color: #808030;">-</span><span style="color: #808030;">-</span> <span style="color: #808030;">></span> <span style="color: #008c00;">0</span><span style="color: #808030;">)</span> <span style="color: purple;">{</span>
assert<span style="color: #808030;">(</span>top<span style="color: #808030;">(</span>heap<span style="color: #808030;">)</span> <span style="color: #808030;">=</span><span style="color: #808030;">=</span> <span style="color: #808030;">-</span>pq<span style="color: #808030;">.</span>top<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
heap <span style="color: #808030;">=</span> pop<span style="color: #808030;">(</span>heap<span style="color: #808030;">)</span><span style="color: purple;">;</span>
pq<span style="color: #808030;">.</span>pop<span style="color: #808030;">(</span><span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #008c00;">0</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
</pre>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com4tag:blogger.com,1999:blog-4816432343216370550.post-8560564997086711132017-06-01T12:06:00.002+08:002017-06-01T12:06:37.670+08:00 Codeforces Round #416 (Div. 2) C. Vladik and Memorable TripProblem Statement:<br />
<a href="http://codeforces.com/contest/811/problem/C"> Codeforces Round #416 (Div. 2) C. Vladik and Memorable Trip</a><br />
<br />
Summary:<br />
An integer array A of size n <= 5000 has entries which ranges from 1 to 5000. We pick disjoint segments of the array such that for each segment S:<br />
1. If i in S, then any j s.t. a[j] == a[i] must also be in S<br />
2. The score of S is computed as the XOR of its elements<br />
Goal is to maximise the sum of scores of the chosen segments.<br />
<br />
Solution:<br />
I like this problem. This is solvable using a dynamic programming approach.<br />
<br />
<a name='more'></a><br />
Suppose dp[i] is the maximum score we can get when we are only allowed to pick segments in A[0...i]. To find dp[i], we can:<br />
1. Skip A[i]. So dp[i] is at least as good as dp[i-1].<br />
2. Form a segment using A[i]. To do this we need to check a few things. First, say the smallest segment we can form (satisfying the above condition) is A[j...k] (i.e. j <= i && i <= k). Now, if k > i, then we cannot use A[i] to form the current segment, as we will be using elements beyond [0..i]. If k == i, then we know that dp[i] is at least as good as dp[j-1] + score of A[j...i].<br />
<br />
With that, the implementation is quite straightforward.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <utility></span>
<span style="color: #557799;">#include <cstring></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> n;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
<span style="color: #333399; font-weight: bold;">int</span> a[<span style="color: #0000dd; font-weight: bold;">5010</span>];
vector<span style="color: #333333;"><</span>pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span>,<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> b;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a[i]);
b.push_back({a[i], i});
}
sort(b.begin(), b.end());
<span style="color: #333399; font-weight: bold;">int</span> r[<span style="color: #0000dd; font-weight: bold;">5010</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #333399; font-weight: bold;">int</span> prev <span style="color: #333333;">=</span> b[<span style="color: #0000dd; font-weight: bold;">0</span>].second;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (b[i].first <span style="color: #333333;">==</span> b[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>].first) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #333399; font-weight: bold;">int</span> val <span style="color: #333333;">=</span> b[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>].first;
<span style="color: #333399; font-weight: bold;">int</span> last <span style="color: #333333;">=</span> b[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>].second;
r[val][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> prev;
r[val][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> last;
prev <span style="color: #333333;">=</span> b[i].second;
}
r[b.back().first][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> prev;
r[b.back().first][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> b.back().second;
<span style="color: #333399; font-weight: bold;">int</span> dp[<span style="color: #0000dd; font-weight: bold;">5010</span>];
<span style="color: #333399; font-weight: bold;">int</span> mark[<span style="color: #0000dd; font-weight: bold;">5010</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
dp[i] <span style="color: #333333;">=</span> dp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>];
<span style="color: #333399; font-weight: bold;">bool</span> can_choose <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
<span style="color: #333399; font-weight: bold;">int</span> last <span style="color: #333333;">=</span> i;
<span style="color: #333399; font-weight: bold;">int</span> cur <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
memset(mark, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #008800; font-weight: bold;">sizeof</span>(mark));
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> i; j <span style="color: #333333;">>=</span> last; <span style="color: #333333;">--</span>j) {
<span style="color: #008800; font-weight: bold;">if</span> (r[a[j]][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">></span> i) {
can_choose <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
}
last <span style="color: #333333;">=</span> min(last, r[a[j]][<span style="color: #0000dd; font-weight: bold;">0</span>]);
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>mark[a[j]]) {
cur <span style="color: #333333;">^=</span> a[j];
mark[a[j]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>can_choose) <span style="color: #008800; font-weight: bold;">continue</span>;
dp[i] <span style="color: #333333;">=</span> max((last <span style="color: #333333;">-</span> <span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;">>=</span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">?</span> dp[last<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">:</span> <span style="color: #0000dd; font-weight: bold;">0</span>) <span style="color: #333333;">+</span> cur, dp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>]);
}
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,dp[n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>]);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-6897954203174370422017-06-01T11:54:00.000+08:002017-06-01T11:54:11.078+08:00Codeforces Round #416 (Div. 2) E. Vladik and Entertaining Flags<div>
Problem Statement:</div>
<a href="http://codeforces.com/contest/811/problem/E">Codeforces Round #416 (Div. 2) E. Vladik and Entertaining Flags</a><br />
Summary:<br />
Given an integer matrix with size m x n with m <= 10, n <= 10^5, find the number of connected components in segment [l, r] of the matrix (i.e. rectangle (0, l) -> (m-1, r)). Two cells belong to the same connected component if they are adjacent (share the same edge) and have the same value.<br />
There are q <= 10^5 such queries.<br />
<br />
Solution:<br />
A cool problem which can be solved using Segment Tree. This is made possible by the following observation: Consider two adjacent segments [l, m] and [m+1, r]. If we know the number of components on each segment, then we can iterate along the cells where the two segments meet to see if we can combine any adjacent components.<br />
<br />
<a name='more'></a>And hence, the number of components in [l, r] is given by the number of components in [l, m] + number of components in [m+1, r] - the number of components we combined.<br />
<br />
To solve the problem then translates to building and querying a segment tree using the above strategy, tracking enough information to perform the merging. In my implementation, on each segment, I keep the component IDs of the cells to the left and right-end the segment.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> mat[<span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>];
<span style="color: #333399; font-weight: bold;">int</span> num_components[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>];
<span style="color: #333399; font-weight: bold;">int</span> group[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #333399; font-weight: bold;">int</span> cur[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #333399; font-weight: bold;">int</span> borrow[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #333399; font-weight: bold;">int</span> n, m;
<span style="color: #333399; font-weight: bold;">int</span> next_id <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">combine</span>(<span style="color: #333399; font-weight: bold;">int</span> M, <span style="color: #333399; font-weight: bold;">int</span> p, <span style="color: #333399; font-weight: bold;">int</span> cur[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>][<span style="color: #0000dd; font-weight: bold;">2</span>], <span style="color: #333399; font-weight: bold;">int</span> group[<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">10</span>][<span style="color: #0000dd; font-weight: bold;">2</span>]) {
<span style="color: #333399; font-weight: bold;">int</span> left <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p;
<span style="color: #333399; font-weight: bold;">int</span> right <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
cur[left][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> group[left][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
cur[left][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> group[left][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
cur[right][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> group[right][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
cur[right][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> group[right][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
}
<span style="color: #333399; font-weight: bold;">int</span> unions <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (cur[left][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">==</span> cur[right][i][<span style="color: #0000dd; font-weight: bold;">0</span>]) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #008800; font-weight: bold;">if</span> (mat[M][i] <span style="color: #333333;">==</span> mat[M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][i]) {
<span style="color: #333399; font-weight: bold;">int</span> c <span style="color: #333333;">=</span> cur[left][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
<span style="color: #333399; font-weight: bold;">int</span> d <span style="color: #333333;">=</span> cur[right][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; j <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>j) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> k <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; k <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">2</span>; <span style="color: #333333;">++</span>k) {
<span style="color: #008800; font-weight: bold;">if</span> (cur[left][j][k] <span style="color: #333333;">==</span> c <span style="color: #333333;">||</span> cur[left][j][k] <span style="color: #333333;">==</span> d) {
cur[left][j][k] <span style="color: #333333;">=</span> min(c,d);
}
<span style="color: #008800; font-weight: bold;">if</span> (cur[right][j][k] <span style="color: #333333;">==</span> c <span style="color: #333333;">||</span> cur[right][j][k] <span style="color: #333333;">==</span> d) {
cur[right][j][k] <span style="color: #333333;">=</span> min(c,d);
}
}
}
<span style="color: #333333;">++</span>unions;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
group[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> cur[left][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
group[p][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> cur[right][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
}
<span style="color: #008800; font-weight: bold;">return</span> unions;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">build</span>(<span style="color: #333399; font-weight: bold;">int</span> L<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #333399; font-weight: bold;">int</span> R<span style="color: #333333;">=</span>n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333399; font-weight: bold;">int</span> p<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (L <span style="color: #333333;">==</span> R) {
num_components[p] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
group[p][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> next_id<span style="color: #333333;">++</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (mat[L][i] <span style="color: #333333;">==</span> mat[L][i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>]) {
group[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> group[p][i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">0</span>];
} <span style="color: #008800; font-weight: bold;">else</span> {
group[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> next_id<span style="color: #333333;">++</span>;
num_components[p]<span style="color: #333333;">++</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
group[p][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> group[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
}
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (L<span style="color: #333333;">+</span>R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
build(L, M, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p);
build(M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #333399; font-weight: bold;">int</span> unions <span style="color: #333333;">=</span> combine(M, p, cur, group);
num_components[p] <span style="color: #333333;">=</span> num_components[<span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p] <span style="color: #333333;">+</span> num_components[<span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">-</span> unions;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">query</span>(<span style="color: #333399; font-weight: bold;">int</span> S, <span style="color: #333399; font-weight: bold;">int</span> T, <span style="color: #333399; font-weight: bold;">int</span> L<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #333399; font-weight: bold;">int</span> R<span style="color: #333333;">=</span>n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333399; font-weight: bold;">int</span> p<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (R<span style="color: #333333;"><</span>S <span style="color: #333333;">||</span> T<span style="color: #333333;"><</span>L) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (S<span style="color: #333333;"><=</span>L <span style="color: #333333;">&&</span> R<span style="color: #333333;"><=</span>T) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
cur[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> group[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
cur[p][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> group[p][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
}
<span style="color: #008800; font-weight: bold;">return</span> num_components[p];
}
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (L<span style="color: #333333;">+</span>R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #333399; font-weight: bold;">int</span> left <span style="color: #333333;">=</span> query(S, T, L, M, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p);
<span style="color: #333399; font-weight: bold;">int</span> right <span style="color: #333333;">=</span> query(S, T, M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">if</span> (left <span style="color: #333333;">>=</span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">&&</span> right <span style="color: #333333;">>=</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #333399; font-weight: bold;">int</span> unions <span style="color: #333333;">=</span> combine(M, p, borrow, cur);
<span style="color: #008800; font-weight: bold;">return</span> left <span style="color: #333333;">+</span> right <span style="color: #333333;">-</span> unions;
}
<span style="color: #333399; font-weight: bold;">int</span> to_copy <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p;
<span style="color: #008800; font-weight: bold;">if</span> (left <span style="color: #333333;">==</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
to_copy <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
cur[p][i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> cur[to_copy][i][<span style="color: #0000dd; font-weight: bold;">0</span>];
cur[p][i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> cur[to_copy][i][<span style="color: #0000dd; font-weight: bold;">1</span>];
}
<span style="color: #008800; font-weight: bold;">return</span> max(left, right);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> q;
scanf(<span style="background-color: #fff0f0;">"%d%d%d"</span>,<span style="color: #333333;">&</span>m,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>q);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;i <span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; j <span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>mat[j][i]);
}
}
build();
<span style="color: #333399; font-weight: bold;">int</span> L,R;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> q; <span style="color: #333333;">++</span>i) {
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>L,<span style="color: #333333;">&</span>R);
L<span style="color: #333333;">--</span>; R<span style="color: #333333;">--</span>;
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,query(L,R));
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-91467937970880346772017-05-28T08:08:00.000+08:002017-05-28T08:08:49.269+08:00Codeforces Round #415 (Div. 2) E. Find a car [or Div. 1 C]Problem Statement:<br />
<a href="http://codeforces.com/contest/810/problem/E"> Codeforces Round #415 (Div. 2) E. Find a car</a><br />
<br />
Paraphrase:<br />
An integer matrix M is defined as:<br />
M[i][j] = the minimum integer x >= 1 such that:<br />
- M[i][k] != x for all k < j<br />
- M[k][j] != x for all k < i<br />
<br />
Example:<br />
1 2 3 4<br />
2 1 4 3<br />
3 4 1 2<br />
4 3 2 1<br />
<br />
Goal: Given a rectangular block in M {(x1, y1), (x2, y2)} and an integer K, compute the sum of elements in that rectangle, but exclude elements whose value is larger than K.<br />
<br />
<br />
<a name='more'></a><br />
<br />
Solution:<br />
<br />
Let's construct the matrices with sizes 1, 2, 4, 8, ...<br />
Size 1:<br />
1<br />
<br />
Size 2:<br />
1 <b>2</b><br />
<b>2</b> 1<br />
<br />
Size 4:<br />
1 2 <b>3 4</b><br />
2 1 <b>4 3</b><br />
<b>3 4</b> 1 2<br />
<b>4 3</b> 2 1<br />
<br />
Size 8:<br />
1 2 3 4 <b>5 6 7 8</b><br />
2 1 4 3 <b>6 5 8 7</b><br />
3 4 1 2 <b>7 8 5 6</b><br />
4 3 2 1 <b>8 7 6 5</b><br />
<b>5 6 7 8</b> 1 2 3 4<br />
<b>6 5 8 7</b> 2 1 4 3<br />
<b>7 8 5 6</b> 3 4 1 2<br />
<b>8 7 6 5</b> 4 3 2 1<br />
<br />
Notice the pattern yet?<br />
<br />
Yes. So given a matrix M[k] with size 2^k, we can construct M[k+1] by appending M[k] and N[k] as follows:<br />
M[k] N[k]<br />
N[k] M[k]<br />
where N[k] is M[k] with all elements incremented by 2^k. (Which can be proven inductively, an exercise for the reader :) )<br />
<br />
Now how is this useful, you ask. This is useful because now you can perform a technique similar to quad tree traversal, which if done correctly, will allow us to answer the query in O(log N) where N is the size of the matrix.<br />
<br />
Notice that each row of M[k+1] consists of values [1, 2, 3, ..., 2 ^ {k+1}] (in some sudoku-like permutation).<br />
Also, M[k] only consists of values in [1, ..., 2^k] while N[k] only of [2^k + 1, ..., 2^{k+1}].<br />
Hence when you split M[k+1] into 4 equal sized quadrants, you get 4 similar construct, they just differ in ranges of values they contain.<br />
You can also check that when you split N[k] into 4 similar sectors, you would also see this pattern holds true.<br />
<br />
<br />
From this point, you may already know what to do next:<br />
1. Start from the whole matrix (you can define it as [1, ..., 2^31] for this problem)<br />
2. If our current space is still not fully inside the target rectangle, split up into 4 quadrants and then recursively proceed (don't forget to carry the information on the range of values our space currently contains). Each quadrant will be our next "space" to check.<br />
3. If our current space does not even intersect with the target rectangle, throw away this quadrant.<br />
4. If our current space is fully contained in our target rectangle, you can quite easily compute the sum of elements in our space that does not exceed K.<br />
<br />
The approach above is correct, but there is one problem. Consider a query such as {(1, 1), (1, 1e9)} for any K. You will end up summing up each of the cells that falls in that rectangle 1e9 times!<br />
One easy fix to this, is to relax our requirement of having our space to be "fully inside" the target rectangle. Instead, as long as one of the side of the space is fully contained in the target rectangle, we can already compute the required sum (Exercise to the reader! Or you can figure it out in the code below). With that, we are sure to have an O(log N) query time.<br />
<br />
Code:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
constexpr <span style="color: #333399; font-weight: bold;">int64_t</span> MOD <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">int64_t</span>) <span style="color: #6600ee; font-weight: bold;">1e9</span> <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">7LL</span>;
<span style="color: #008800; font-weight: bold;">struct</span> quad {
<span style="color: #333399; font-weight: bold;">int64_t</span> x1, y1;
<span style="color: #333399; font-weight: bold;">int64_t</span> x2, y2;
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">contains</span>(<span style="color: #008800; font-weight: bold;">const</span> quad<span style="color: #333333;">&</span> other) {
<span style="color: #008800; font-weight: bold;">return</span> (x1 <span style="color: #333333;"><=</span> other.x1 <span style="color: #333333;">&&</span> other.x2 <span style="color: #333333;"><=</span> x2) <span style="color: #333333;">||</span>
(y1 <span style="color: #333333;"><=</span> other.y1 <span style="color: #333333;">&&</span> other.y2 <span style="color: #333333;"><=</span> y2);
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">intersects</span>(<span style="color: #008800; font-weight: bold;">const</span> quad<span style="color: #333333;">&</span> other) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #333333;">!</span>(x2 <span style="color: #333333;"><</span> other.x1 <span style="color: #333333;">||</span> x1 <span style="color: #333333;">></span> other.x2
<span style="color: #333333;">||</span> y2 <span style="color: #333333;"><</span> other.y1 <span style="color: #333333;">||</span> y1 <span style="color: #333333;">></span> other.y2);
}
};
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">contribute</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> L, <span style="color: #333399; font-weight: bold;">int64_t</span> R, <span style="color: #333399; font-weight: bold;">int64_t</span> k, <span style="color: #333399; font-weight: bold;">int64_t</span> n) {
<span style="color: #008800; font-weight: bold;">if</span> (k <span style="color: #333333;"><</span> L) <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> A <span style="color: #333333;">=</span> L <span style="color: #333333;">+</span> min(k, R);
<span style="color: #333399; font-weight: bold;">int64_t</span> B <span style="color: #333333;">=</span> min(k,R) <span style="color: #333333;">-</span> L <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">if</span> (A <span style="color: #333333;">%</span> <span style="color: #0000dd; font-weight: bold;">2LL</span>) B <span style="color: #333333;">/=</span> <span style="color: #0000dd; font-weight: bold;">2LL</span>;
<span style="color: #008800; font-weight: bold;">else</span> A <span style="color: #333333;">/=</span> <span style="color: #0000dd; font-weight: bold;">2LL</span>;
A <span style="color: #333333;">%=</span> MOD;
B <span style="color: #333333;">%=</span> MOD;
<span style="color: #008800; font-weight: bold;">return</span> (((A <span style="color: #333333;">*</span> B) <span style="color: #333333;">%</span> MOD) <span style="color: #333333;">*</span> n) <span style="color: #333333;">%</span> MOD;
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">dfs</span>(quad space, <span style="color: #333399; font-weight: bold;">int64_t</span> L, <span style="color: #333399; font-weight: bold;">int64_t</span> R, quad target, <span style="color: #333399; font-weight: bold;">int64_t</span> k) {
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>target.intersects(space)) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (target.contains(space)) {
<span style="color: #333399; font-weight: bold;">int64_t</span> n <span style="color: #333333;">=</span> min(
min(target.x2, space.x2) <span style="color: #333333;">-</span> max(target.x1, space.x1) <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span>,
min(target.y2, space.y2) <span style="color: #333333;">-</span> max(target.y1, space.y1) <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span>
);
<span style="color: #008800; font-weight: bold;">return</span> contribute(L, R, k, n <span style="color: #333333;">%</span> MOD);
}
<span style="color: #333399; font-weight: bold;">int64_t</span> ans <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> M <span style="color: #333333;">=</span> (L <span style="color: #333333;">+</span> R) <span style="color: #333333;">/</span> <span style="color: #0000dd; font-weight: bold;">2LL</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> m <span style="color: #333333;">=</span> (R <span style="color: #333333;">-</span> L) <span style="color: #333333;">/</span> <span style="color: #0000dd; font-weight: bold;">2LL</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">2</span>; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; j <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">2</span>; <span style="color: #333333;">++</span>j) {
quad next_space;
next_space.x1 <span style="color: #333333;">=</span> space.x1 <span style="color: #333333;">+</span> (i <span style="color: #333333;">?</span> m <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;">:</span> <span style="color: #0000dd; font-weight: bold;">0</span>);
next_space.x2 <span style="color: #333333;">=</span> (i <span style="color: #333333;">?</span> space.x2 <span style="color: #333333;">:</span> space.x1 <span style="color: #333333;">+</span> m);
next_space.y1 <span style="color: #333333;">=</span> space.y1 <span style="color: #333333;">+</span> (j <span style="color: #333333;">?</span> m <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;">:</span> <span style="color: #0000dd; font-weight: bold;">0</span>);
next_space.y2 <span style="color: #333333;">=</span> (j <span style="color: #333333;">?</span> space.y2 <span style="color: #333333;">:</span> space.y1 <span style="color: #333333;">+</span> m);
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">^</span> j) {
ans <span style="color: #333333;">+=</span> dfs(next_space, M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R, target, k);
ans <span style="color: #333333;">%=</span> MOD;
} <span style="color: #008800; font-weight: bold;">else</span> {
ans <span style="color: #333333;">+=</span> dfs(next_space, L, M, target, k);
ans <span style="color: #333333;">%=</span> MOD;
}
}
}
<span style="color: #008800; font-weight: bold;">return</span> ans;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">solve</span>(<span style="color: #333399; font-weight: bold;">int</span> x1, <span style="color: #333399; font-weight: bold;">int</span> x2, <span style="color: #333399; font-weight: bold;">int</span> y1, <span style="color: #333399; font-weight: bold;">int</span> y2, <span style="color: #333399; font-weight: bold;">int64_t</span> k) {
<span style="color: #333399; font-weight: bold;">int64_t</span> L <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> R <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span> <span style="color: #333333;"><<</span> <span style="color: #0000dd; font-weight: bold;">31</span>;
quad space;
space.x1 <span style="color: #333333;">=</span> space.y1 <span style="color: #333333;">=</span> L;
space.x2 <span style="color: #333333;">=</span> space.y2 <span style="color: #333333;">=</span> R;
quad target;
target.x1 <span style="color: #333333;">=</span> x1;
target.x2 <span style="color: #333333;">=</span> x2;
target.y1 <span style="color: #333333;">=</span> y1;
target.y2 <span style="color: #333333;">=</span> y2;
cout <span style="color: #333333;"><<</span> dfs(space, L, R, target, k) <span style="color: #333333;"><<</span> endl;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> q;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>q);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> q; <span style="color: #333333;">++</span>i) {
<span style="color: #333399; font-weight: bold;">int64_t</span> x1,x2,y1,y2,k;
cin <span style="color: #333333;">>></span> x1 <span style="color: #333333;">>></span> y1 <span style="color: #333333;">>></span> x2 <span style="color: #333333;">>></span> y2 <span style="color: #333333;">>></span> k;
solve(x1,x2,y1,y2,k);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-21961694111567182152017-03-16T19:07:00.000+08:002017-03-16T19:07:41.721+08:00UVa 434 - Matty's BlocksProblem Statement:<br />
<a href="https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=375">UVa 434 - Matty's Blocks</a><br />
<br />
Summary:<br />
This problem pertains to a matrix of size K x K, where each entry is a non-negative integer.<br />
Let the maximum values on each row be max_row[0 .. K-1], and the maximum values on each column be max_col[0 .. K - 1].<br />
<br />
E.g. <br />
[ 1 4 2 5 3 ] --> 5<br />
[ 8 1 7 6 0 ] --> 8<br />
[ 3 3 4 1 5 ] --> 5 max_row<br />
[ 6 5 0 3 2 ] --> 6<br />
[ 2 4 1 6 6 ] --> 6<br />
v v v v v<br />
8 5 7 6 5<br />
max_col<br />
<br />
Our job is to fill in the matrix to fulfil those requirements. In general there are more than one way to do it. Compute:<br />
1. Minimum sum of entries possible.<br />
2. Maximum sum of entries possible.<br />
<br />
Note that no constraint is placed on K in the original problem statement. It can be small, it can be very large.<br />
<br />
<br />
<a name='more'></a><br />
<br />
Solution:<br />
I like this problem, especially if you think of K as being a large values ( > 1 million). How would you do it?<br />
<br />
Turns out this problem can be solved by means of sorting and scanning operations. Let's figure out how.<br />
<br />
<u>Minimum possible sum</u><br />
Let's say we are in the middle of filling in the matrix by focusing on a column or a row at a time.<br />
<br />
Consider i-th row of our matrix, whose maximum entry must be V = max_row[i]. Surely, V must occur in one of the columns in this row (Why?). So, we only want to fill in V once on one of the column so as to minimise the final total sum.<br />
<br />
Surely, we cannot place V on column j where max_col[j] is smaller than V, because it will violate the max_col[j]'s requirement. Hence V can only be placed on columns j where V <= max_col[j].<br />
<br />
If all of the column j has max_col[j] > V, then it is guaranteed that those columns j must be empty (Why?). Hence we can choose any one column to place V and proceed to the next row. (In this case, while we fulfil max_row[i], we still need one more entry on column j to fulfil max_col[j].)<br />
<br />
On the other hand, in there are columns j where V = max_col[j]. If these columns are empty, then we should fill in V in one of these columns. This will allow us to fulfil both max_row[i] and max_col[j] with one entry. On the other hand, say that those columns are not empty. Then we know that to achieve minimum possible sum, those columns must contain V! (Otherwise, say it contains other V' < V, then since max_col[j] = V, it must have V somewhere else in the column to fulfil max_col[j], making V' redundant).<br />
<br />
From the above, we see that the order in which we consider the columns and rows are not important.<br />
Hence, instead of simulating the process, we can simply sort both max_row and max_col, and scan through each array using 2 pointers approach (similar to a merge operation in merge sort) which will bring down the complexity from O(K^2) to O(K lg K) + O(2K).<br />
<u><br /></u>
<u>Maximum possible sum</u><br />
Extending the idea from minimum possible sum, now instead of choosing a column j to fill in, we fill every single column with V in row i where max_col[j] >= V (and vice versa when we are considering columns). This is a much simpler process than the previous one. However the simulation will take O(K^2). Instead, we can also use the sorted max_row and max_col with 2 pointers scan as well. We can compute the total entries in each row and each column one by one, and then subtract the intersection. This will also achieve a complexity of O(K lg K) + O(2K).<br />
<br />
The implementation below will give a clear idea of the 2 pointers approach.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <string></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <map></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> K;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> values[<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">min_blocks</span>() {
<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>, j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> ans <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">while</span> (i <span style="color: #333333;"><</span> K <span style="color: #333333;">&&</span> j <span style="color: #333333;"><</span> K) {
<span style="color: #333399; font-weight: bold;">int</span> minval <span style="color: #333333;">=</span> min(values[<span style="color: #0000dd; font-weight: bold;">0</span>][i], values[<span style="color: #0000dd; font-weight: bold;">1</span>][j]);
ans <span style="color: #333333;">+=</span> minval;
<span style="color: #008800; font-weight: bold;">if</span> (values[<span style="color: #0000dd; font-weight: bold;">0</span>][i] <span style="color: #333333;">==</span> minval) {
<span style="color: #333333;">++</span>i;
}
<span style="color: #008800; font-weight: bold;">if</span> (values[<span style="color: #0000dd; font-weight: bold;">1</span>][j] <span style="color: #333333;">==</span> minval) {
<span style="color: #333333;">++</span>j;
}
}
<span style="color: #008800; font-weight: bold;">while</span> (i <span style="color: #333333;"><</span> K) {
ans <span style="color: #333333;">+=</span> values[<span style="color: #0000dd; font-weight: bold;">0</span>][i<span style="color: #333333;">++</span>];
}
<span style="color: #008800; font-weight: bold;">while</span> (j <span style="color: #333333;"><</span> K) {
ans <span style="color: #333333;">+=</span> values[<span style="color: #0000dd; font-weight: bold;">1</span>][j<span style="color: #333333;">++</span>];
}
<span style="color: #008800; font-weight: bold;">return</span> ans;
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">total_larger_than</span>(vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> first, vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> second) {
<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> ans <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> K; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">while</span> (j <span style="color: #333333;"><</span> K <span style="color: #333333;">&&</span> second[j] <span style="color: #333333;"><</span> first[i]) <span style="color: #333333;">++</span>j;
ans <span style="color: #333333;">+=</span> first[i] <span style="color: #333333;">*</span> (K <span style="color: #333333;">-</span> j);
}
<span style="color: #008800; font-weight: bold;">return</span> ans;
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">overlap</span>(vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> first, vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> second) {
<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>, j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> ans <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">while</span> (i <span style="color: #333333;"><</span> K <span style="color: #333333;">&&</span> j <span style="color: #333333;"><</span> K) {
<span style="color: #333399; font-weight: bold;">int</span> cur_val <span style="color: #333333;">=</span> min(first[i], second[j]);
<span style="color: #333399; font-weight: bold;">int</span> len_1 <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>, len_2 <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">while</span> (i <span style="color: #333333;"><</span> K <span style="color: #333333;">&&</span> first[i] <span style="color: #333333;">==</span> cur_val) {
<span style="color: #333333;">++</span>i;
<span style="color: #333333;">++</span>len_1;
}
<span style="color: #008800; font-weight: bold;">while</span> (j <span style="color: #333333;"><</span> K <span style="color: #333333;">&&</span> second[j] <span style="color: #333333;">==</span> cur_val) {
<span style="color: #333333;">++</span>j;
<span style="color: #333333;">++</span>len_2;
}
ans <span style="color: #333333;">+=</span> (<span style="color: #333399; font-weight: bold;">int64_t</span>) cur_val <span style="color: #333333;">*</span> len_1 <span style="color: #333333;">*</span> len_2;
}
<span style="color: #008800; font-weight: bold;">return</span> ans;
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">max_blocks</span>() {
<span style="color: #333399; font-weight: bold;">int64_t</span> ans <span style="color: #333333;">=</span> total_larger_than(values[<span style="color: #0000dd; font-weight: bold;">0</span>], values[<span style="color: #0000dd; font-weight: bold;">1</span>]);
ans <span style="color: #333333;">+=</span> total_larger_than(values[<span style="color: #0000dd; font-weight: bold;">1</span>], values[<span style="color: #0000dd; font-weight: bold;">0</span>]);
ans <span style="color: #333333;">-=</span> overlap(values[<span style="color: #0000dd; font-weight: bold;">0</span>], values[<span style="color: #0000dd; font-weight: bold;">1</span>]);
<span style="color: #008800; font-weight: bold;">return</span> ans;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">read</span>() {
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>K);
values[<span style="color: #0000dd; font-weight: bold;">0</span>].clear();
values[<span style="color: #0000dd; font-weight: bold;">1</span>].clear();
<span style="color: #333399; font-weight: bold;">int</span> val;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; j <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">2</span>; <span style="color: #333333;">++</span>j) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> K; <span style="color: #333333;">++</span>i) {
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>val);
values[j].push_back(val);
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">2</span>; <span style="color: #333333;">++</span>i) {
sort(values[i].begin(), values[i].end());
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>() {
<span style="color: #333399; font-weight: bold;">int</span> tc;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>tc);
<span style="color: #008800; font-weight: bold;">while</span> (tc <span style="color: #333333;">--></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
read();
<span style="color: #333399; font-weight: bold;">int64_t</span> N <span style="color: #333333;">=</span> min_blocks();
<span style="color: #333399; font-weight: bold;">int64_t</span> M <span style="color: #333333;">=</span> max_blocks();
printf(<span style="background-color: #fff0f0;">"Matty needs at least %lld blocks, and can add at most %lld extra blocks.</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, N, M<span style="color: #333333;">-</span>N);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-88366326631456469082017-02-27T02:14:00.002+08:002017-02-27T02:16:09.621+08:00a bit of algo: LZW CompressionLZW compression is a magic show. I am left awe-struck as the algorithm compresses and uncompresses bits of data. The magic is not in the fact that it does compress the data, no, that's the boring part. The magic is in the simplicity and elegance of it.<br />
<br />
<b>Compression</b><br />
Given a string "bananababa", the algorithm starts with a code table. We initialize the code table with the following entries:<br />
<br />
0 - a<br />
1 - b<br />
2 - n<br />
<br />
This is called the initial code table.<br />
<br />
LZW then iterates through the letters in the string while also updating the code table. The algorithm is simply:<br />
<br />
buffer := empty;<br />
for c in str:<br />
if buffer + c is in code_table:<br />
buffer := buffer + c;<br />
else:<br />
output code_table[buffer];<br />
add (next_index_number++, buffer + c) into code_table;<br />
buffer := c;<br />
output code_table[buffer];<br />
<br />
That's it! So with our example "bananababa", we get:<br />
<br />
<br />
<a name='more'></a><br /><br />
<br />
1. b<br />
buffer := b;<br />
2. a [ba]<br />
add (3, ba) to code_table<br />
buffer := a;<br />
output := 1;<br />
3. n [ban]<br />
add (4, an) to code_table<br />
buffer := n;<br />
output := 1, 0;<br />
4. a [bana]<br />
add (5, na) to code_table<br />
buffer := a;<br />
output := 1, 0, 2;<br />
5. n [banan]<br />
buffer := an;<br />
6. a [banana]<br />
add (6, ana);<br />
buffer := a;<br />
output := 1, 0, 2, 4;<br />
7. b [bananab]<br />
add (7, ab);<br />
buffer := b;<br />
output := 1, 0, 2, 4, 0;<br />
8. a [bananaba]<br />
buffer := ba;<br />
9. b [bananabab]<br />
add (8, bab)<br />
buffer := b;<br />
output := 1, 0, 2, 4, 0, 3;<br />
10. a [bananababa]<br />
buffer := ba;<br />
11. EOF<br />
flush buffer<br />
output := 1, 0, 2, 4, 0, 3, 3;<br />
<br />
Hence the end result of the compression from [1,0,2,0,2,0,1,0,1,0] (bananababa) is [1,0,2,4,0,3,3].<br />
As the size of code_table can get really big, usually a simple scheme such as limiting the code_table size to some threshold is used.<br />
<br />
<b>Decompression</b><br />
You might think that the decompression is simple because we just need to perform code lookup on the entire code table. However the decompression actually needs only the compressed result and the same initial code table! The procedure will rebuilt exactly the same code_table in the end after reading the decompressed data.<br />
<br />
The decompression algorithm is magical:<br />
<br />
prev_code := compressed_data[0];<br />
for code in compressed_data[1, end]:<br />
output code_table[prev_code];<br />
if code in code_table:<br />
next_entry := code_table[prev_code] + first letter of code_table[code];<br />
else:<br />
// Special case, see below.<br />
next_entry := code_table[prev_code] + first letter of code_table[prev_code];<br />
add (next_index_number++, next_entry) into code_table;<br />
prev_code := code;<br />
output code_table[prev_code];<br />
<br />
<br />
The first case of the if statement can be intuitively understood as this: In the compression algorithm, we are outputting code only when buffer + c is not found in code_table. Hence in the decompression procedure, we are simply reverting the compression logic: code_table[prev_code] is exactly the "buffer" and the first letter of code_table[code] is c.<br />
<br />
Example decompression using [1,0,2,4,0,3,3] and the same initial code table:<br />
<br />
0 - a<br />
1 - b<br />
2 - n<br />
<br />
1. Initialize prev_code = 1.<br />
2. 0 [1,0]<br />
output := b;<br />
add (3, ba) to code_table;<br />
prev_code := 0;<br />
3. 2 [1,0,2]<br />
output := ba;<br />
add (4, an) to code_table;<br />
prev_code := 2;<br />
4. 4 [1,0,2,4]<br />
output := ban;<br />
add (5, na) to code_table;<br />
prev_code := 4;<br />
5. 0 [1,0,2,4,0]<br />
output := banan;<br />
add (6, ana) to code_table;<br />
prev_code := 0;<br />
6. 3 [1,0,2,4,0,3]<br />
output := banana;<br />
add (7, ab);<br />
prev_code := 3;<br />
7. 3 [1,0,2,4,0,3]<br />
output := bananaba;<br />
add (8, bab);<br />
prev_code := 3;<br />
8. EOF: flush prev_code;<br />
output := bananababa;<br />
<br />
The else branch of the if condition is a special case in which 'code' is not found in our code_table yet. Consider string "abababab", starting with code table (0, a), (1, b):<br />
<br />
The compression produces:<br />
1. a --> buffer := a<br />
2. b --> buffer := b add (2, ab) output 0<br />
3. a --> buffer := a add (3, ba) output 1<br />
4. b --> buffer := ab<br />
5. a --> buffer := a add (4, aba) output 2<br />
6. b --> buffer := ab<br />
7. a --> buffer := aba<br />
8. b --> buffer := b add (5, abab) output 4<br />
9. EOF --> flush buffer, output 1<br />
with compression result [0, 1, 2, 4, 1].<br />
<br />
The decompression procedure without the "else" branch is hence:<br />
1. Initialize prev_code := 0;<br />
2. 1 [0, 1]<br />
output := a;<br />
add (2, ab);<br />
prev_code := 1;<br />
3. 2 [0, 1, 2]<br />
output := ab;<br />
add (3, ba);<br />
prev_code := 2;<br />
4. 4 [0, 1, 2, 4]<br />
output := abab;<br />
add (4, code_table[2] + first_letter(code_table[4])) <<<<< ERROR!<br />
-----<br />
<br />
Hence we need to handle this special case. In short, the key observation is that the first letter of code_table['prev_code'] must be the same as that of 'code' for this to happen.<br />
<br />
This scenario happens when 'code' is exactly the next index number entry to the code_table*. Meaning, it must be the newest entry of the compression procedure before 'code' is output. Let X be that newest entry, and Y be the buffer value just before encountering c such that buffer+c is not in the code_table. Then c must be X[0], such that Y + X[0] is X. This means that X starts and ends with the same character. Finally, it means that the first character of Y is the same as that of X. Therefore we can use the first letter of prev_code as the proxy to the real value of first_letter(code_table['code']).<br />
<br />
[*Additional note: How do we know that is true? Suppose the the compression algorithm outputs code C as the n-th code output, then its code_table must has n entries (ignoring initial entries). Hence C <= n. However when the decompression reads in C, it has only n-1 code_table entries (ignoring initial entries). Hence for C to be bigger than the code table entry, it must be > n-1 but it cannot be larger than n. Hence C = n.]<br />
<br />
That's all! LZW is quite easy to implement and it's a good algorithm to know since it might come in handy one day.<br />
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-64547536335586570922016-08-24T18:08:00.000+08:002016-08-24T18:08:50.626+08:00Codeforces Round #365 (Div. 2) - E. Mishka and DivisorsProblem Statement:<br />
<a href="http://codeforces.com/contest/703/problem/E">http://codeforces.com/contest/703/problem/E</a><br />
<br />
Summary:<br />
Given an array of n <= 1000 integers a[i] <= 10^12, and an integer k <= 10^12. Find subset of the array which product of the elements is divisible by k, such that the size of the subset is minimised. If more than one such subsets exist, return the one with smallest sum over the elements.<br />
<br />
<a name='more'></a><br />
Solution:<br />
The tricky part is to define the DP state to keep track. Suppose we solve a much simpler form of the problem: compute the subset of minimum size such that the product is divisible by k. Let dp[i][d] be the subset of a[1..i] with minimum size (minimum subsequence length) which product is divisible by d. For d0 | d1 (d1 is divisible by d0), it is true that dp[i][d1] >= dp[i][d0]. (Based on the observation that if S is the minimum subset S which product is divisible by d1, then S will also be divisible by d0, which means that length of S is the upper limit for dp[i][d0].)<br />
<br />
To compute dp[i][d], we have two choices:<br />
1. Pick a[i] into our subset. This gives us dp[i-1][d/gcd(d, a[i])] + 1. In other words, the minimum length if we pick a[i] is achieved by finding the subset in [1..i-1] that is divisible by the remaining factor of d that is not covered by a[i]. This is the key relationship in the DP transition that allows us to solve the problem. (Correctness argument: If we pick a[i], then we need to find the minimum of dp[i-1][X] for all X such that a[i]*X is divisible by d. The smallest of such X is exactly d/gcd(a[i], d), which also corresponds to the desired minimum.)<br />
2. Don't pick a[i], then the minimum subset possible is derived from dp[i-1][d].<br />
Hence dp[i][d] = min(dp[i-1][d/gcd(d, a[i])] + 1, d[i-1][d]).<br />
<br />
To reduce the dp state, we can instead compute the prime factors of k, and hence notice that what matters is to keep track of the prime factors in each of a[i]. As it turns out, the number of divisors possible given k is still in the order of 10^3. I think one can check for this by enumerating over all possible prime factors and multiplicity, maximising the number of prime factors by choosing smaller primes.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> primes;
<span style="color: #333399; font-weight: bold;">int</span> prime_marker[<span style="color: #0000dd; font-weight: bold;">1000000</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">PrecomputePrimes</span>() {
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">int</span> MAX_PRIME <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1000000</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span>; i <span style="color: #333333;">*</span> i <span style="color: #333333;"><</span> MAX_PRIME; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> i; i <span style="color: #333333;">*</span> j <span style="color: #333333;"><</span> MAX_PRIME; <span style="color: #333333;">++</span>j) {
prime_marker[i<span style="color: #333333;">*</span>j]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span>; i <span style="color: #333333;"><</span> MAX_PRIME; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (prime_marker[i]) <span style="color: #008800; font-weight: bold;">continue</span>;
primes.push_back(i);
}
}
<span style="color: #888888;">// Prime factors of K.</span>
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> prime_factors;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> factor_max_power;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ComputePrimeFactors</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> val) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> primes.size(); <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (val <span style="color: #333333;">%</span> primes[i] <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
prime_factors.push_back(primes[i]);
factor_max_power.push_back(<span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #008800; font-weight: bold;">while</span> (val <span style="color: #333333;">%</span> primes[i] <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
val <span style="color: #333333;">/=</span> primes[i];
factor_max_power.back()<span style="color: #333333;">++</span>;
}
}
}
<span style="color: #008800; font-weight: bold;">if</span> (val <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">1000000</span>) {
prime_factors.push_back(val);
factor_max_power.push_back(<span style="color: #0000dd; font-weight: bold;">1</span>);
}
}
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> arr;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> cofactor_power;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ComputeCofactorPower</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> val) {
cofactor_power.resize(prime_factors.size());
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> prime_factors.size(); <span style="color: #333333;">++</span>i) {
cofactor_power[i] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">if</span> (val <span style="color: #333333;">%</span> prime_factors[i] <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #008800; font-weight: bold;">while</span> (val <span style="color: #333333;">%</span> prime_factors[i] <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
val <span style="color: #333333;">/=</span> prime_factors[i];
cofactor_power[i]<span style="color: #333333;">++</span>;
}
}
}
}
<span style="color: #888888;">// Indices Hash</span>
<span style="color: #888888;">// E.g. [i][j][k] = i * NJ * NK + j * NK + k.</span>
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> basis;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">InitializeBasis</span>() {
basis.resize(prime_factors.size());
basis[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>; i <span style="color: #333333;"><</span> prime_factors.size(); <span style="color: #333333;">++</span>i) {
basis[i] <span style="color: #333333;">=</span> basis[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">*</span> (factor_max_power[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">MapToIndices</span>(<span style="color: #333399; font-weight: bold;">int</span> hash, vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>*</span> indices <span style="color: #888888;">/* OUT */</span>) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> basis.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>; i <span style="color: #333333;">>=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; <span style="color: #333333;">--</span>i) {
(<span style="color: #333333;">*</span>indices)[i] <span style="color: #333333;">=</span> hash <span style="color: #333333;">/</span> basis[i];
hash <span style="color: #333333;">-=</span> (<span style="color: #333333;">*</span>indices)[i] <span style="color: #333333;">*</span> basis[i];
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">IndicesToHash</span>(<span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> indices) {
<span style="color: #333399; font-weight: bold;">int</span> hash <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> indices.size(); <span style="color: #333333;">++</span>i) {
hash <span style="color: #333333;">+=</span> indices[i]<span style="color: #333333;">*</span>basis[i];
}
<span style="color: #008800; font-weight: bold;">return</span> hash;
}
vector<span style="color: #333333;"><</span>vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> hash_indices;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">InitHashIndices</span>(<span style="color: #333399; font-weight: bold;">int</span> max_hash) {
hash_indices.resize(max_hash, vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span>(basis.size()));
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> max_hash; <span style="color: #333333;">++</span>i) {
MapToIndices(i, <span style="color: #333333;">&</span>hash_indices[i]);
}
}
<span style="color: #008800; font-weight: bold;">struct</span> DpState {
<span style="color: #333399; font-weight: bold;">int</span> length <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">100000</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> cost <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> parent;
<span style="color: #333399; font-weight: bold;">bool</span> is_chosen <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
DpState(<span style="color: #333399; font-weight: bold;">int</span> length, <span style="color: #333399; font-weight: bold;">int64_t</span> cost, <span style="color: #333399; font-weight: bold;">int</span> parent, <span style="color: #333399; font-weight: bold;">bool</span> is_chosen)
<span style="color: #333333;">:</span> length(length), cost(cost), parent(parent), is_chosen(is_chosen) {}
DpState() {}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #008800; font-weight: bold;">operator</span><span style="color: #333333;"><</span>(<span style="color: #008800; font-weight: bold;">const</span> DpState<span style="color: #333333;">&</span> other) <span style="color: #008800; font-weight: bold;">const</span> {
<span style="color: #008800; font-weight: bold;">if</span> (length <span style="color: #333333;">==</span> other.length) <span style="color: #008800; font-weight: bold;">return</span> cost <span style="color: #333333;"><</span> other.cost;
<span style="color: #008800; font-weight: bold;">return</span> length <span style="color: #333333;"><</span> other.length;
}
};
DpState dp[<span style="color: #0000dd; font-weight: bold;">1003</span>][<span style="color: #0000dd; font-weight: bold;">7000</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">UpdateDP</span>(<span style="color: #333399; font-weight: bold;">int</span> cur, <span style="color: #333399; font-weight: bold;">int</span> hash, <span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> indices) {
<span style="color: #008800; font-weight: bold;">if</span> (cur <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (hash <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
dp[cur][hash] <span style="color: #333333;">=</span> DpState{<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #007020;">false</span>};
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #333399; font-weight: bold;">bool</span> is_divisible <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> indices.size(); <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (indices[i] <span style="color: #333333;">></span> cofactor_power[i]) {
is_divisible <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
<span style="color: #008800; font-weight: bold;">if</span> (is_divisible) {
dp[cur][hash] <span style="color: #333333;">=</span> DpState{
<span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #888888;">/* length */</span>,
arr[cur] <span style="color: #888888;">/* cost */</span>,
<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #888888;">/* parent */</span>,
<span style="color: #007020;">true</span>
};
}
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #888888;">// Case 1: Take arr[cur].</span>
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> prev_indices(indices.size());
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> indices.size(); <span style="color: #333333;">++</span>i) {
prev_indices[i] <span style="color: #333333;">=</span> max(<span style="color: #0000dd; font-weight: bold;">0</span>, indices[i] <span style="color: #333333;">-</span> cofactor_power[i]);
}
<span style="color: #333399; font-weight: bold;">int</span> prev_hash <span style="color: #333333;">=</span> IndicesToHash(prev_indices);
DpState state1 <span style="color: #333333;">=</span> {
dp[cur<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][prev_hash].length <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">1</span>,
dp[cur<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][prev_hash].cost <span style="color: #333333;">+</span> arr[cur],
prev_hash,
<span style="color: #007020;">true</span>
};
<span style="color: #888888;">// Case 2: Don't take arr[cur].</span>
DpState state2 <span style="color: #333333;">=</span> {
dp[cur<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][hash].length,
dp[cur<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][hash].cost,
hash,
<span style="color: #007020;">false</span>
};
<span style="color: #008800; font-weight: bold;">if</span> (state1 <span style="color: #333333;"><</span> state2) {
dp[cur][hash] <span style="color: #333333;">=</span> state1;
} <span style="color: #008800; font-weight: bold;">else</span> {
dp[cur][hash] <span style="color: #333333;">=</span> state2;
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #333399; font-weight: bold;">int64_t</span> k;
PrecomputePrimes();
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
cin <span style="color: #333333;">>></span> k;
<span style="color: #333399; font-weight: bold;">int64_t</span> val;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
cin <span style="color: #333333;">>></span> val;
arr.push_back(val);
}
<span style="color: #888888;">// Special Case: d = 1.</span>
<span style="color: #008800; font-weight: bold;">if</span> (k <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #333399; font-weight: bold;">int</span> lowest_index <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (arr[i] <span style="color: #333333;"><</span> arr[lowest_index]) lowest_index <span style="color: #333333;">=</span> i;
}
printf(<span style="background-color: #fff0f0;">"1</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,lowest_index<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
ComputePrimeFactors(k);
InitializeBasis();
<span style="color: #333399; font-weight: bold;">int</span> max_hash <span style="color: #333333;">=</span> basis.back() <span style="color: #333333;">*</span> (factor_max_power.back()<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
InitHashIndices(max_hash);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> n; <span style="color: #333333;">++</span>i) {
ComputeCofactorPower(arr[i]);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> hash <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; hash <span style="color: #333333;"><</span> max_hash; <span style="color: #333333;">++</span>hash) {
UpdateDP(i, hash, hash_indices[hash]);
}
}
<span style="color: #333399; font-weight: bold;">int</span> cur_hash <span style="color: #333333;">=</span> max_hash<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">if</span> (dp[n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][cur_hash].length <span style="color: #333333;">>=</span> <span style="color: #0000dd; font-weight: bold;">100000</span>) {
printf(<span style="background-color: #fff0f0;">"-1</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, dp[n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][cur_hash].length);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>; i<span style="color: #333333;">>=</span><span style="color: #0000dd; font-weight: bold;">0</span>; <span style="color: #333333;">--</span>i) {
<span style="color: #008800; font-weight: bold;">if</span>(dp[i][cur_hash].is_chosen) {
printf(<span style="background-color: #fff0f0;">"%d "</span>, i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
cur_hash <span style="color: #333333;">=</span> dp[i][cur_hash].parent;
}
printf(<span style="background-color: #fff0f0;">"</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
The time complexity is hence O(n * number of primes * number of possible divisors).Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-49638093146477552442016-08-22T21:08:00.001+08:002016-08-22T21:09:12.363+08:00Codeforces Round #365 (Div. 2) - D. Mishka and Interesting sumProblem Statement:<br />
<a href="http://codeforces.com/contest/703/problem/D">http://codeforces.com/contest/703/problem/D</a><br />
<br />
Summary:<br />
Given array a[i] for N <= 10^6 integers, and M <= 10^6 queries (L, R): collect all integers in a[L..R] that occur even number of times, and compute their XOR. E.g. for a = {1, 2, 2, 3, 4, 4}, query (2, 7) returns 2 XOR 4 = 6. If no such element in a particular query, return 0.<br />
<br />
<a name='more'></a>Solution:<br />
The solution employs interesting segment tree update technique. The observation is that the answer to the query (L, R) can be computed as the XOR of:<br />
1. XOR of all elements in L to R (where each integer that occurs even number of times will cancel each other out) with<br />
2. XOR of all distinct elements in L to R.<br />
<br />
Part 1 is trivial, part 2 is the hard part. The idea is to process the queries in prefix order. Sort the queries in increasing R order. For each integers x that we will encounter from left to right while we are processing the queries, we keep track of the last_pos[x] the right most position where we have seen this number.<br />
<br />
Hence if we want to find the XOR of all distinct integers from L to R, all we need to do is to XOR all integers x on which the last_pos[x] is >= L. By maintaining a segment tree, we can compute and update the XOR in O(log N). For each new position of x, the mechanic of the update will be: first update segment tree at old position last_pos[x] to 0, then update last_pos[x] to newest last position, and finally update the segment tree at new last_pos[x] to x.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <map></span>
<span style="color: #557799;">#include <utility></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #008800; font-weight: bold;">struct</span> Query {
<span style="color: #333399; font-weight: bold;">int</span> left;
<span style="color: #333399; font-weight: bold;">int</span> right;
<span style="color: #333399; font-weight: bold;">int</span> id;
};
<span style="color: #333399; font-weight: bold;">int</span> n;
map<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span>,<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> last_pos;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> segtree; <span style="color: #888888;">// Containing XOR of distinct elements from [L, R].</span>
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">UpdateSegtree</span>(<span style="color: #333399; font-weight: bold;">int</span> i, <span style="color: #333399; font-weight: bold;">int</span> val, <span style="color: #333399; font-weight: bold;">int</span> p<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333399; font-weight: bold;">int</span> L<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #333399; font-weight: bold;">int</span> R<span style="color: #333333;">=</span>n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (R <span style="color: #333333;"><</span> i <span style="color: #333333;">||</span> i <span style="color: #333333;"><</span> L) <span style="color: #008800; font-weight: bold;">return</span>;
<span style="color: #008800; font-weight: bold;">if</span> (L <span style="color: #333333;">==</span> R <span style="color: #333333;">&&</span> L <span style="color: #333333;">==</span> i) {
segtree[p] <span style="color: #333333;">=</span> val;
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (L<span style="color: #333333;">+</span>R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
UpdateSegtree(i, val, p<span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">2</span>, L, M);
UpdateSegtree(i, val, p<span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R);
segtree[p] <span style="color: #333333;">=</span> segtree[<span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p] <span style="color: #333333;">^</span> segtree[<span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>];
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">RangeQuery</span>(<span style="color: #333399; font-weight: bold;">int</span> S, <span style="color: #333399; font-weight: bold;">int</span> T, <span style="color: #333399; font-weight: bold;">int</span> p<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333399; font-weight: bold;">int</span> L<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #333399; font-weight: bold;">int</span> R<span style="color: #333333;">=</span>n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (R<span style="color: #333333;"><</span>S <span style="color: #333333;">||</span> T<span style="color: #333333;"><</span>L) <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">if</span> (S <span style="color: #333333;"><=</span> L <span style="color: #333333;">&&</span> R <span style="color: #333333;"><=</span> T) <span style="color: #008800; font-weight: bold;">return</span> segtree[p];
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (L<span style="color: #333333;">+</span>R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #008800; font-weight: bold;">return</span> RangeQuery(S, T, p<span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">2</span>, L, M) <span style="color: #333333;">^</span> RangeQuery(S, T, p<span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> a(n, <span style="color: #0000dd; font-weight: bold;">0</span>);
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> xor_sum(n, <span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a[i]);
xor_sum[i] <span style="color: #333333;">=</span> a[i];
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) xor_sum[i] <span style="color: #333333;">^=</span> xor_sum[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>];
}
segtree.resize(<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span>n, <span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #333399; font-weight: bold;">int</span> m;
vector<span style="color: #333333;"><</span>Query<span style="color: #333333;">></span> queries;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>m);
<span style="color: #333399; font-weight: bold;">int</span> l,r;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>l,<span style="color: #333333;">&</span>r);
l<span style="color: #333333;">--</span>; r<span style="color: #333333;">--</span>;
queries.push_back({l, r, i});
}
sort(queries.begin(), queries.end(), [](<span style="color: #008800; font-weight: bold;">const</span> Query<span style="color: #333333;">&</span> L, <span style="color: #008800; font-weight: bold;">const</span> Query<span style="color: #333333;">&</span> R) {
<span style="color: #008800; font-weight: bold;">return</span> L.right <span style="color: #333333;"><</span> R.right;
});
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> ans(m, <span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #333399; font-weight: bold;">int</span> last_index <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
l <span style="color: #333333;">=</span> queries[i].left;
r <span style="color: #333333;">=</span> queries[i].right;
<span style="color: #008800; font-weight: bold;">while</span> (last_index <span style="color: #333333;"><=</span> r) {
<span style="color: #008800; font-weight: bold;">auto</span> it <span style="color: #333333;">=</span> last_pos.find(a[last_index]);
<span style="color: #008800; font-weight: bold;">if</span> (it <span style="color: #333333;">!=</span> last_pos.end()) {
UpdateSegtree(it<span style="color: #333333;">-></span>second, <span style="color: #0000dd; font-weight: bold;">0</span>);
}
last_pos[a[last_index]] <span style="color: #333333;">=</span> last_index;
UpdateSegtree(last_index, a[last_index]);
<span style="color: #333333;">++</span>last_index;
}
ans[queries[i].id] <span style="color: #333333;">=</span> xor_sum[r] <span style="color: #333333;">^</span> (l<span style="color: #333333;">></span><span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">?</span> xor_sum[l<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">:</span> <span style="color: #0000dd; font-weight: bold;">0</span>) <span style="color: #333333;">^</span> RangeQuery(l, r);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> m; <span style="color: #333333;">++</span>i) {
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,ans[i]);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
Corollary: to compute property of distinct integers in (L, R), we can service the queries in prefix order (increasing R ordering) and extend the prefix from left to right, while keeping track of each last position of the integers along the way.Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-82696572433155984932016-08-15T15:33:00.001+08:002016-08-24T18:10:39.279+08:00Codeforces Round #366 (Div. 1) - B. Ant ManProblem Statement:<br />
<a href="http://codeforces.com/contest/704/problem/B">http://codeforces.com/contest/704/problem/B</a><br />
<br />
Summary:<br />
We are given a graph with nodes 1 to n, such that the cost of going from node i to node j is:<br />
1) |x[i] - x[j]| + c[i] + b[j] if j < i<br />
2) |x[i] - x[j]| + d[i] + a[j] if i < j.<br />
Given a start node s and an end node e, find a hamiltonian path from s to e (hamiltonian path: a path that visits all nodes in the graph once) such that the total cost is minimised. (Also, x[i] is monotonically increasing. n <= 5000).<br />
<br />
<a name='more'></a><br />
<br />
Solution:<br />
Tough and fun problem. The solution uses dynamic programming over the prefix of the nodes.<br />
<br />
Let's simplify the cost function.<br />
<br />
For the case where j < i, we have:<br />
|x[i]-x[j]| + c[i] + b[j] = (c[i] + x[i]) + (b[j] - x[j]).<br />
<br />
For the case where i < j, we have:<br />
|x[i]-x[j]| + d[i] + a[j] = (d[i] - x[i]) + (a[j] + x[j]).<br />
<br />
See that we can group terms of the same index together. Hence we can pre-compute the arrays left_out[i] = c[i] + x[i], left_in[j] = b[j]-x[j], right_out[i] = d[i]-x[i] and right_in[j] = a[j]+x[j].<br />
It has the nice property that if we choose to jump to the right from node i to node j for example, we can can easily compute the cost as right_out[i] + right_in[j].<br />
<br />
Now we can discuss the DP formulation. The idea is to analyse the property of the optimal path. The path will form a DAG. Moreover, each node along the path will have one degree in and one degree out, except node s which has one degree out, and node e which has one degree in. In the spirit of DP, what if we only consider the first i nodes 1 to i (i.e. throw away nodes [i+1 to n] from the path)?<br />
<br />
In that case, our induced graph will contain several fragment of paths.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">(induced graph)
<span style="color: #333333;">+--------------------</span> <span style="color: #333333;">|</span>[<span style="color: black; font-weight: bold;">in</span>]
V <span style="color: #333333;">|</span>
[<span style="color: #0000dd; font-weight: bold;">1</span>] [<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">--></span>[<span style="color: #0000dd; font-weight: bold;">3</span>] [<span style="color: #0000dd; font-weight: bold;">4</span>]<span style="color: #333333;">---></span> <span style="color: #333333;">|</span>[out]
<span style="color: #333333;">^</span> \ <span style="color: #333333;">|</span>
<span style="color: #333333;">|</span> \ <span style="color: #333333;">|</span>
<span style="color: #333333;">|</span> <span style="color: #333333;">+------></span> <span style="color: #333333;">|</span>[in_out]
<span style="color: #333333;">+---------------</span> <span style="color: #333333;">|</span>
truncation
</pre>
</div>
<br />
One important observation is that the two ends of the path must not be in this induced graph (otherwise the original path is not connected), and there cannot be a cycle in the induced graph (obviously since the original path is a DAG).<br />
<br />
Hence we have three types of fragments:<br />
1. 'in_out': The fragment does not contain the end points of the original path. Hence it has one in-degree edge and one out-degree edge.<br />
2. 'in' : The fragment ends with node e. It will hence only have one in-degree edge.<br />
3. 'out': The fragment starts with node s. It will hence only have one out-degree edge.<br />
<br />
From that, we can already form a DP formulation. Let dp[i][in][out][in_out] be the dp state, where dp[n][0][0][0] is the minimum cost of a hamiltonian path that starts with s and ends with e. Hence dp[i][i][j][k] is the minimum cost associated with having an induced graph with i fragments with type 'in', j fragments with type 'out', and k fragments with type 'k'.<br />
For each i, consider adding i to the current induced graph [1..i-1].<br />
When i is not e and s, we will have to add an in-degree and out-degree edge. There are 4 ways we can do this (i.e. left-in left-out, left-in right-out, right-in left-out, right-in right-out). When i is either e or s, we can only add either an in-degree or out-degree edge respectively. Finally we also need to consider the special case where i is the n node, where we will tie in the fragments left in the induced graph into one final path. The following code is the implementation of the approach.<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
constexpr <span style="color: #333399; font-weight: bold;">int</span> NMAX <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">5002</span>;
constexpr <span style="color: #333399; font-weight: bold;">int64_t</span> INF <span style="color: #333333;">=</span> <span style="color: #6600ee; font-weight: bold;">1e18</span>;
<span style="color: #333399; font-weight: bold;">int</span> n, e, s;
<span style="color: #333399; font-weight: bold;">int64_t</span> dp[<span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">2</span>][NMAX];
<span style="color: #333399; font-weight: bold;">int64_t</span> left_in[NMAX], left_out[NMAX], right_in[NMAX], right_out[NMAX];
<span style="color: #333399; font-weight: bold;">int</span> a[NMAX], b[NMAX], c[NMAX], d[NMAX], x[NMAX];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Compute</span>(<span style="color: #333399; font-weight: bold;">int</span> i, <span style="color: #333399; font-weight: bold;">int</span> in, <span style="color: #333399; font-weight: bold;">int</span> out, <span style="color: #333399; font-weight: bold;">int</span> in_out) {
<span style="color: #333399; font-weight: bold;">int</span> prev <span style="color: #333333;">=</span> (i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>)<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">*</span> cur_state <span style="color: #333333;">=</span> <span style="color: #333333;">&</span>dp[i<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">2</span>][in][out][in_out];
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> INF;
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">==</span> n) {
<span style="color: #888888;">// Special case: i == n.</span>
<span style="color: #888888;">// Only compute this state if in and out are both 0.</span>
<span style="color: #008800; font-weight: bold;">if</span> (in <span style="color: #333333;">||</span> out) <span style="color: #008800; font-weight: bold;">return</span>;
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">==</span> e) {
<span style="color: #888888;">// --> x.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][in_out] <span style="color: #333333;">+</span> right_in[i]);
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">==</span> s) {
<span style="color: #888888;">// <-- x.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][out][in_out] <span style="color: #333333;">+</span> left_out[i]);
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #888888;">// --> <-- x: uses one OUT and one IN to close the path.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][out<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][in_out] <span style="color: #333333;">+</span> right_in[i] <span style="color: #333333;">+</span> left_out[i]);
}
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">==</span> s) {
<span style="color: #888888;">// <-- x or x --></span>
<span style="color: #008800; font-weight: bold;">if</span> (out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #888888;">// <-- x: Combine with the IN of in_out. in_out is reduced by one. out is increased by one.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][in_out<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">+</span> left_out[i]);
<span style="color: #888888;">// x -->: out is increased by one.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][in_out] <span style="color: #333333;">+</span> right_out[i]);
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">==</span> e) {
<span style="color: #888888;">// --> x or x <--</span>
<span style="color: #008800; font-weight: bold;">if</span> (in <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #888888;">// --> x: Combine with one OUT from in_out. in_out is decreased by one, in increases by 1.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][out][in_out<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">+</span> right_in[i]);
<span style="color: #888888;">// x <-- : in increases by one.</span>
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][out][in_out] <span style="color: #333333;">+</span> left_in[i]);
}
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #888888;">// --> x -->: uses one OUT from either in_out or out, and introduces one OUT of the same type.</span>
<span style="color: #008800; font-weight: bold;">if</span> (out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> in_out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out][in_out] <span style="color: #333333;">+</span> right_in[i] <span style="color: #333333;">+</span> right_out[i]);
}
<span style="color: #888888;">// <-- x <--: uses one IN from either in_out or in, and introduces one IN of the same type.</span>
<span style="color: #008800; font-weight: bold;">if</span> (in <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> in_out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out][in_out] <span style="color: #333333;">+</span> left_out[i] <span style="color: #333333;">+</span> left_in[i]);
}
<span style="color: #888888;">// --> <-- x: uses one OUT and one IN. Two choices:</span>
<span style="color: #888888;">// - Connect two in_out into one in_out, or</span>
<span style="color: #888888;">// - Connect in with in_out or out with in_out (either case, in_out is reduced by one, in and out is preserved).</span>
<span style="color: #008800; font-weight: bold;">if</span> (in <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> in_out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out][in_out<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">+</span> right_in[i] <span style="color: #333333;">+</span> left_out[i]);
}
<span style="color: #888888;">// x --> <--: adds one IN and one OUT. Hence adds 1 in_out.</span>
<span style="color: #008800; font-weight: bold;">if</span> (in_out <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">0</span>) {
<span style="color: #333333;">*</span>cur_state <span style="color: #333333;">=</span> min(<span style="color: #333333;">*</span>cur_state, dp[prev][in][out][in_out<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">+</span> left_in[i] <span style="color: #333333;">+</span> right_out[i]);
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Solve</span>() {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
left_out[i] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>x[i]<span style="color: #333333;">+</span>c[i];
left_in[i] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>b[i]<span style="color: #333333;">-</span>x[i];
right_out[i] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>d[i]<span style="color: #333333;">-</span>x[i];
right_in[i] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>x[i]<span style="color: #333333;">+</span>a[i];
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> in<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;in<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>in){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> out<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;out<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>out){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> in_out<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;in_out<span style="color: #333333;"><</span>NMAX;<span style="color: #333333;">++</span>in_out){
dp[i][in][out][in_out] <span style="color: #333333;">=</span> INF;
}
}
}
}
dp[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> in<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;in<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>in){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> out<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;out<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>out){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> in_out<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;in_out<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>in_out){
Compute(i, in, out, in_out);
}
}
}
}
cout <span style="color: #333333;"><<</span> dp[n<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;"><<</span> endl;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>s,<span style="color: #333333;">&</span>e);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>x[i]);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a[i]);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>b[i]);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>c[i]);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>d[i]);
}
Solve();
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
Notice that since we can only have at most one 'in' and one 'out' fragment, the DP state is actually O(4n^2). To reduce memory requirement, also notice that for each computation of dp[i][...], we only need to know the results of dp[i-1][...] (the previous state), hence we can get away with just caching the values of dp[i-1][...] while discarding all values of dp[1..i-2][...].Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-85411545799913509112016-08-13T15:39:00.000+08:002016-08-14T18:18:42.146+08:00Kalman Filter - Preliminary StudyI am embarking on a project that works with sensors. Sensor readings are noisy, so they need to be filtered. There are many ways to filter a stream of noisy data, and one that I just learnt is called Kalman Filter. A good place to learn about it is: <a href="http://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/">http://www.bzarg.com/p/how-a-kalman-filter-works-in-pictures/</a>. Here I am going to discuss about this technique mostly for my own future reference.<br />
<br />
<br />
<a name='more'></a>It seems that the main motivation behind this technique is that the product of two Gaussian functions is also Gaussian. This relationship allows us to combine the result of future measurements with current predictions to come up with a more optimal guess in a recursive manner.<br />
<br />
Motivating example: we are tracking a vehicle using a GPS. We can't tell exactly where the vehicle is. But we can draw a circle in which we believe where the vehicle should be located. The centre of the circle being the point we most strongly believe where the vehicle is, though it can be located anywhere further away from that point with decreasing probability.<br />
<br />
In this kind of example, if we model the thing that we want to keep track of as Gaussian, then what we need is the mean \(x\) and covariance matrix \(P\). As of the example above, over time the vehicle will move, and hence \(x\) will also change over time, as well as \(P\) which will get larger as time passes (we are getting more and more uncertain of where the vehicle is). Our main objective is to keep track of \(x\) and \(P\) and at the same time find a way to bound \(P\).<br />
<br />
Given \(x_k\) and \(P_k\) the mean and covariance values at time k, we can derive \(x_{k+1}\) and \(P_{k+1}\) the prediction of the mean and covariance at time k+1. Let \(F_k\) be the matrix that represents the update from \(x_k\) to \(x_{k+1}\). Then we have \(x_{k+1} = F_k x_k\). Furthermore, \(P_{k+1} = Cov(F_kx_k) = F_kP_kF_k^T\). This is called the "prediction" stage of Kalman Filter. To factor in external forces and process error, we can extend the above formulation into a more general one: \(x_{k+1} = F_kx_k + C_k\) while \(P_{k+1} = F_kP_kF_k^T + D_k\) for some \(C_k\) and \(D_k\) that represent external force and process error respectively.<br />
<br />
One timestep ahead, at time k+1, suppose that we also have a reading of \(x\) (which is not accurate). Let's call this reading \(y_{k+1}\), and say that the measurement also follows Gaussian distribution with covariance matrix \(Q_{k+1}\). The idea is to correct our prediction \(x_{k+1}\) and \(P_{k+1}\) using the new noisy readings. The way Kalman Filter resolves the difference is by multiplying both the distribution N(x, P) and N(y, Q) to come up with a new distribution with a new mean and variance that is optimal based on x, P, y and Q. As it turns out, N(x, P) N(y, Q) is also Gaussian: \(N(x, P) N(y, Q) = c \exp\left\{-\frac{1}{2}\left( (v-x)^TP^{-1}(v-x) + (v-y)^TQ^{-1}(v-y) \right)\right\}\) (for some constant c) can be rewritten as \( d \exp \left\{ -\frac{1}{2} \left( (v-u)^TS^{-1}(v-u) \right) \right\} \) (for some constant d) where<br />
\(S^{-1} = P^{-1} + Q^{-1}\) and \(u = SP^{-1}x + SQ^{-1}y\). (by simple grouping of terms and terms comparison, and also using the fact that covariance matrix is symmetric).<br />
<br />
Here, it is clear that we can compute S and u which are the "correction" of our prediction x, P based on our reading y, Q. The formulation of Kalman Filter can be derived from the above:<br />
Let \(K = P(P+Q)^{-1} \). K is called the Kalman gain. We will show that:<br />
(1). \(S = P - KP\) and,<br />
(2). \(u = x + K(y-x)\).<br />
For (1): We can reverse engineer the process. Let's suppose that we do not know what K is. Then by letting \(S = (P^{-1}+Q^{-1})^{-1} = P - KP\), we get \(I = P(P^{-1}+Q^{-1}) - KP(P^{-1}+Q^{-1})\) which simplifies to \(K = PQ^{-1}(I+PQ^{-1})^{-1}\). However, notice that \(P+Q)Q^{-1} = PQ^{-1} + I\), which implies \(Q^{-1}(PQ^{-1}+I)^{-1}=(P+Q)^{-1}\). Hence we can rewrite K as \(K = P(P+Q)^{-1}\). This also implies that \(S = P-KP\).<br />
For (2): From \(u = SP^{-1}x + SQ^{-1}y\), we can substitute (1) into that expression to deduce (2).<br />
<br />
Together, (1) and (2) forms the "update" stage of the process. The new value S and u is then used for the next prediction of x and P, and the process repeats itself. (1) and (2) can be generalized further in case that we need to transform \(x\) to the dimension of \(y\) by providing a transformation matrix \(H\), s.t. \(Hx\) is in the dimension of \(y\), and \(HPH^T\) is the covariance of \(Hx\).<br />
<br />
The next step for me is to make use of this filter and see the effectiveness of this technique. I'll post the results in a future post.<br />
<br />
UPDATE:<br />
Implementation of Kalman Filter can be found here:<a href="https://github.com/prajogotio/expriment-kalmanfilter">https://github.com/prajogotio/expriment-kalmanfilter</a>. Interesting fact: process error is actually one important factor that allows the filter to converge nearer to reading values.<br />
<br />
Preliminary result:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2fCDKUMV9SBSJh7zgrbCJakXi5-ZspNniBnZbmbGlZ0dwhZmq2siPH1XnBw98bLlpqWt5P89-8mGAkq-_-ZkZoOEdffWk3xm_zg0LYAJEHZTalInMQAhOO8irpuKlHIUisiGVnCFFF9I/s1600/Screen+Shot+2016-08-14+at+6.11.39+pm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2fCDKUMV9SBSJh7zgrbCJakXi5-ZspNniBnZbmbGlZ0dwhZmq2siPH1XnBw98bLlpqWt5P89-8mGAkq-_-ZkZoOEdffWk3xm_zg0LYAJEHZTalInMQAhOO8irpuKlHIUisiGVnCFFF9I/s640/Screen+Shot+2016-08-14+at+6.11.39+pm.png" width="640" /></a></div>
<br />
The blue line represents the raw accelerometer readings on one of the axis, while the smoother red line represents the filtered data. It is clear that the filter does effectively smoothen the graph, but at the same time the picture also shows that further experimentation on the parameters of the filter is necessary for its application.Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-282519192735783782016-08-09T11:52:00.002+08:002016-08-09T12:13:23.569+08:00Codeforces Round #253 (Div. 1) - A. Borya and Hanabi [Revisited]Problem Statement:<br />
<a href="http://codeforces.com/contest/442/problem/A">http://codeforces.com/contest/442/problem/A</a><br />
<br />
Summary:<br />
A deck of cards, each card has a name (R, G, B, Y, W) and a value (1, 2, 3, 4, 5). Given an array of cards of unknown names and values, we can ask for hints to identify each of the cards. There are two types of hints: name hint or value hint. For example, when we ask a name hint 'R', all cards with name 'R' will be marked. Similarly, a value hint '2' will mark all cards with value '2'. What is the minimum number of hints needed so that we can identify all the cards exactly? (Note that some cards might be duplicated in the array).<br />
<br />
Solution:<br />
I have written about this problem previously (<a href="https://abitofcs.blogspot.sg/2015/01/codeforces-442a-borya-and-hanabi.html">https://abitofcs.blogspot.sg/2015/01/codeforces-442a-borya-and-hanabi.html</a>), however after solving this problem once again I learnt that it can be tackled from a different perspective using bitmap.<br />
<br />
<a name='more'></a>Imagine asking for a name hint 'R'. We will then know all the cards that have name 'R', although we might not know what values those card have. If for each of the card, we keep track of a bitmap value of the form RGBYW12345, we can set the bit on position 'R' to indicate this knowledge. Hence if we ask for 10 hints (maximum number of hints), we will be able to identify all cards based on the bitmap values. In fact, if there are no duplicate cards in the array, then if all the bitmap values are different, we can already identify all the cards. Furthermore, notice that the order of the hints do not matter because the final bitmaps from a given set of hints are always the same regardless on which hint is evaluated first.<br />
<br />
The problem, however, allows for duplicated cards. Turns out, it is not an issue because duplicated cards will always have the same bitmap values. Therefore we can simply combine duplicated cards as one.<br />
<br />
Below is the implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #888888;">#include <cstdio></span>
<span style="color: #888888;">#include <algorithm></span>
<span style="color: #888888;">#include <string></span>
<span style="color: #888888;">#include <iostream></span>
<span style="color: #888888;">#include <vector></span>
using namespace std;
<span style="color: #007020;">int</span> n;
<span style="color: #007020;">int</span> res <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">9999</span>;
<span style="color: #007020;">int</span> cnt[<span style="color: #0000dd; font-weight: bold;">1200</span>];
vector<span style="color: #333333;"><</span><span style="color: #007020;">int</span><span style="color: #333333;">></span> cardlist;
<span style="color: #007020;">int</span> bmap[<span style="color: #0000dd; font-weight: bold;">5</span>][<span style="color: #0000dd; font-weight: bold;">5</span>];
void Check(<span style="color: #007020;">int</span> bm) {
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">5</span>;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #007020;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">5</span>;<span style="color: #333333;">++</span>j){
bmap[i][j]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
}
}
<span style="color: #007020;">bool</span> duplicate <span style="color: #333333;">=</span> false;
<span style="color: #007020;">int</span> hints <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #007020;">int</span> k<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;k<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">10</span>;<span style="color: #333333;">++</span>k){
<span style="color: #008800; font-weight: bold;">if</span> (<span style="background-color: #ffaaaa; color: red;">!</span>(bm <span style="color: #333333;">&</span> (<span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;"><<</span>k))) <span style="color: #008800; font-weight: bold;">continue</span>;
hints<span style="color: #333333;">++</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">5</span>;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (k <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">5</span>) {
bmap[k][i] <span style="color: #333333;">|=</span> (<span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;"><<</span> k);
} <span style="color: #008800; font-weight: bold;">else</span> {
bmap[i][k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">5</span>] <span style="color: #333333;">|=</span> (<span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;"><<</span> k);
}
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>cardlist<span style="color: #333333;">.</span>size();<span style="color: #333333;">++</span>i){
<span style="color: #007020;">int</span> name <span style="color: #333333;">=</span> cardlist[i]<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">10</span>;
<span style="color: #007020;">int</span> val <span style="color: #333333;">=</span> cardlist[i]<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">10</span>;
cnt[bmap[name][val]]<span style="color: #333333;">++</span>;
<span style="color: #008800; font-weight: bold;">if</span> (cnt[bmap[name][val]] <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
duplicate <span style="color: #333333;">=</span> true;
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>cardlist<span style="color: #333333;">.</span>size();<span style="color: #333333;">++</span>i){
<span style="color: #007020;">int</span> name <span style="color: #333333;">=</span> cardlist[i]<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">10</span>;
<span style="color: #007020;">int</span> val <span style="color: #333333;">=</span> cardlist[i]<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">10</span>;
cnt[bmap[name][val]]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="background-color: #ffaaaa; color: red;">!</span>duplicate) {
res <span style="color: #333333;">=</span> <span style="color: #007020;">min</span>(hints, res);
}
}
<span style="color: #007020;">int</span> main(){
scanf(<span style="background-color: #fff0f0;">"</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0;">"</span>,<span style="color: #333333;">&</span>n);
string card;
vector<span style="color: #333333;"><</span>string<span style="color: #333333;">></span> temp;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
cin <span style="color: #333333;">>></span> card;
temp<span style="color: #333333;">.</span>push_back(card);
}
sort(temp<span style="color: #333333;">.</span>begin(), temp<span style="color: #333333;">.</span>end());
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (i <span style="color: #333333;">&&</span> temp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">==</span> temp[i]) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #007020;">int</span> name <span style="color: #333333;">=</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
switch(temp[i][<span style="color: #0000dd; font-weight: bold;">0</span>]) {
case <span style="background-color: #fff0f0;">'R'</span>:
name <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
case <span style="background-color: #fff0f0;">'G'</span>:
name <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
case <span style="background-color: #fff0f0;">'B'</span>:
name <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
case <span style="background-color: #fff0f0;">'Y'</span>:
name <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">3</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
case <span style="background-color: #fff0f0;">'W'</span>:
name <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">4</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
}
cardlist<span style="color: #333333;">.</span>push_back(name<span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">10</span><span style="color: #333333;">+</span>(temp[i][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">-</span><span style="background-color: #fff0f0;">'1'</span>));
}
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #007020;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>(<span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;"><<</span><span style="color: #0000dd; font-weight: bold;">10</span>);<span style="color: #333333;">++</span>i){
Check(i);
}
printf(<span style="background-color: #fff0f0;">"</span><span style="background-color: #eeeeee;">%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,res);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
The time complexity is O(2^k k^2 N) where k is the total number of names and values (10), while N is the number of cards (at most 100).Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-90830477401998753252016-07-23T17:03:00.000+08:002016-08-07T11:00:35.743+08:00Codeforces Round #360 (Div. 1) - D. Dividing Kingdom IIProblem Statement:<br />
<a href="http://codeforces.com/contest/687/problem/D">http://codeforces.com/contest/687/problem/D</a><br />
<br />
Summary:<br />
n < 1000 vertices, m = O(n^2) weighted edges (numbered from 1 to m), and q < 1000 queries (L, R) to consider all edges number L to R, group the endpoints of the edges into two groups 0 or 1, and minimize the weight of the edge with the largest weight having its endpoints in the same group.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
The idea to solve the problem is interesting. Consider the query (L, R). If we go through all the edges numbered L to R in decreasing weight order, then for each edge (u, v) we will attempt to join the vertices u and v, which leads to three possibilities:<br />
1. u and v are not in the same connected component. This means that u and v can be connected together and their connected components will form one larger connected components which is bipartite.<br />
2. u and v are already in the same connected component. Before addition of edge u-v, the connected component is bipartite. Hence we need to check if the addition of u-v still maintains this property. This means we must check if u and v are in different group/color. If they are of different group, we can join them without problem.<br />
3. Otherwise, u and v are of the same group/color. Hence u-v is the first edge such that its addition causes its connected component to be not bipartite. We conclude that the weight of edge u-v is the answer for the current query (L, R). [Contemplating about this further, here is why this is correct: we have proven to ourselves by construction that the answer to the query (L, R) is at most the weight of u-v, because we can indeed create bipartite components using all the edges of higher weight before u-v. To prove that the answer cannot be smaller than u-v, first observe that a cycle of odd length cannot be bipartite. Hence when u-v connects two vertices of the same color, we conclude that u-v introduces an odd cycle to the connected component. Hence there the edges from the highest weight to u-v cannot be bipartite due to the existence of the odd cycle, which means u-v must be the smallest possible answer to the query].<br />
<br />
The implementation given here is not the most efficient one asymptotically (the expected solution seems to use segment tree of 'interesting' edges). It follows exactly the idea described above.<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #008800; font-weight: bold;">struct</span> Edge {
<span style="color: #333399; font-weight: bold;">int</span> u, v, weight, id;
};
<span style="color: #333399; font-weight: bold;">int</span> n, m, q;
<span style="color: #333399; font-weight: bold;">int</span> color[<span style="color: #0000dd; font-weight: bold;">1010</span>], par[<span style="color: #0000dd; font-weight: bold;">1010</span>], sz[<span style="color: #0000dd; font-weight: bold;">1010</span>];
vector<span style="color: #333333;"><</span>Edge<span style="color: #333333;">></span> edges;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Init</span>(){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
par[i]<span style="color: #333333;">=</span>i;
color[i]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
sz[i]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">FindPar</span>(<span style="color: #333399; font-weight: bold;">int</span> u) {
<span style="color: #008800; font-weight: bold;">return</span> par[u] <span style="color: #333333;">==</span> u <span style="color: #333333;">?</span> u <span style="color: #333333;">:</span> (par[u] <span style="color: #333333;">=</span> FindPar(par[u]));
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">Combine</span>(<span style="color: #333399; font-weight: bold;">int</span> u, <span style="color: #333399; font-weight: bold;">int</span> v) {
<span style="color: #333399; font-weight: bold;">int</span> x <span style="color: #333333;">=</span> FindPar(u);
<span style="color: #333399; font-weight: bold;">int</span> y <span style="color: #333333;">=</span> FindPar(v);
<span style="color: #008800; font-weight: bold;">if</span> (x <span style="color: #333333;">==</span> y) {
<span style="color: #008800; font-weight: bold;">return</span> color[u] <span style="color: #333333;">!=</span> color[v];
}
<span style="color: #008800; font-weight: bold;">if</span> (sz[x] <span style="color: #333333;">></span> sz[y]) {
swap(x, y);
swap(u, v);
}
<span style="color: #008800; font-weight: bold;">if</span> (color[u] <span style="color: #333333;">==</span> color[v]) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (FindPar(i)<span style="color: #333333;">==</span>x) color[i] <span style="color: #333333;">^=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
par[x] <span style="color: #333333;">=</span> y;
<span style="color: #008800; font-weight: bold;">if</span> (sz[x] <span style="color: #333333;">==</span> sz[y]) sz[y]<span style="color: #333333;">++</span>;
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">Query</span>(<span style="color: #333399; font-weight: bold;">int</span> L, <span style="color: #333399; font-weight: bold;">int</span> R) {
Init();
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span>(L <span style="color: #333333;"><=</span> edges[i].id <span style="color: #333333;">&&</span> edges[i].id <span style="color: #333333;"><=</span> R) {
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>Combine(edges[i].u, edges[i].v)) <span style="color: #008800; font-weight: bold;">return</span> edges[i].weight;
}
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>m,<span style="color: #333333;">&</span>q);
<span style="color: #333399; font-weight: bold;">int</span> u,v,w;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d%d%d"</span>,<span style="color: #333333;">&</span>u,<span style="color: #333333;">&</span>v,<span style="color: #333333;">&</span>w);
<span style="color: #008800; font-weight: bold;">if</span> (u <span style="color: #333333;">></span> v) swap(u,v);
<span style="color: #333333;">--</span>u; <span style="color: #333333;">--</span>v;
edges.push_back({u, v, w, i});
}
sort(edges.begin(), edges.end(),
[](<span style="color: #008800; font-weight: bold;">const</span> Edge<span style="color: #333333;">&</span> L, <span style="color: #008800; font-weight: bold;">const</span> Edge<span style="color: #333333;">&</span> R) {
<span style="color: #008800; font-weight: bold;">return</span> L.weight <span style="color: #333333;">></span> R.weight;
});
<span style="color: #333399; font-weight: bold;">int</span> l,r;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> qq<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;qq<span style="color: #333333;"><</span>q;<span style="color: #333333;">++</span>qq){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>l,<span style="color: #333333;">&</span>r);
l<span style="color: #333333;">--</span>;r<span style="color: #333333;">--</span>;
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,Query(l,r));
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-75678975001386302392016-07-19T13:29:00.001+08:002016-08-07T11:00:55.866+08:00Codeforces Round #360 (Div. 1) - C. The Values You Can MakeProblem Statement:<br />
<a href="http://codeforces.com/contest/687/problem/C">http://codeforces.com/contest/687/problem/C</a><br />
<br />
Summary:<br />
n, k <= 500, with n integers c[i] <= 500, output all x such that there exists a subset S of c with sum k, and S has a subset with sum x.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
The dynamic programming used in this problem is a little bit different. Let dp[i][j][k] equals to 1 if in prefix c[0..i] there exists two disjoint subsets with sum j and k respectively. Then we have dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-c[i]][k], dp[i-1][j][k-c[i]]).<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> n, k;
<span style="color: #333399; font-weight: bold;">int</span> c[<span style="color: #0000dd; font-weight: bold;">510</span>];
<span style="color: #333399; font-weight: bold;">bool</span> dp[<span style="color: #0000dd; font-weight: bold;">510</span>][<span style="color: #0000dd; font-weight: bold;">510</span>][<span style="color: #0000dd; font-weight: bold;">510</span>];
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>k);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>c[i]);}
dp[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
dp[<span style="color: #0000dd; font-weight: bold;">0</span>][c[<span style="color: #0000dd; font-weight: bold;">0</span>]][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
dp[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>][c[<span style="color: #0000dd; font-weight: bold;">0</span>]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
dp[i][<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> s<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;s<span style="color: #333333;"><=</span>k;<span style="color: #333333;">++</span>s){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> t<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;t<span style="color: #333333;"><=</span>k;<span style="color: #333333;">++</span>t){
<span style="color: #008800; font-weight: bold;">if</span> (s<span style="color: #333333;">-</span>c[i]<span style="color: #333333;">>=</span><span style="color: #0000dd; font-weight: bold;">0</span>) dp[i][s][t] <span style="color: #333333;">=</span> max(dp[i][s][t], dp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][s<span style="color: #333333;">-</span>c[i]][t]);
<span style="color: #008800; font-weight: bold;">if</span> (t<span style="color: #333333;">-</span>c[i]<span style="color: #333333;">>=</span><span style="color: #0000dd; font-weight: bold;">0</span>) dp[i][s][t] <span style="color: #333333;">=</span> max(dp[i][s][t], dp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][s][t<span style="color: #333333;">-</span>c[i]]);
dp[i][s][t] <span style="color: #333333;">=</span> max(dp[i][s][t], dp[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][s][t]);
}
}
}
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> ans;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> s<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;s<span style="color: #333333;"><=</span>k;<span style="color: #333333;">++</span>s){
<span style="color: #008800; font-weight: bold;">if</span> (dp[n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>][s][k<span style="color: #333333;">-</span>s]) ans.push_back(s);
}
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, (<span style="color: #333399; font-weight: bold;">int</span>)ans.size());
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">:</span> ans) {
printf(<span style="background-color: #fff0f0;">"%d "</span>, i);
}
printf(<span style="background-color: #fff0f0;">"</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-53697919600219719732016-07-18T14:20:00.000+08:002016-08-07T11:01:20.486+08:00Codeforces Round #360 (Div. 1) - B. Remainders GameProblem Statement:<br />
<a href="http://codeforces.com/contest/687/problem/B">http://codeforces.com/contest/687/problem/B</a><br />
<br />
Summary:<br />
Given integer n, k < 1M, and n numbers c[1], ..., c[n] < 1M, decide whether we can always guess for all unknown integer x, what x mod k is if x mod c[i] is known for all i.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
This problem has a cool solution. For a given c[i] and k, we cannot always decide what x is if there exist x and y such that x = y mod c[i] but x != y mod k. This is equivalent to x-y = 0 mod c[i] and x-y != 0 mod k, which means c[i] divides x-y, but k does not divides x-y. This means x-y = LM where L is lcm(c[1], c[2], ..., c[n]) and M is the rest of the factor. Since k does not divide x-y, then k does not divides L. Hence we conclude that if we cannot always decide what x is, then k does not divide L.<br />
<br />
Now let's go the other direction. If k does not divide L, then we can choose x = 2L and y = L, such that x-y = L which is divisible by all c[i] but not k. This is equivalent to saying x = y mod c[i] but x != y mod k, meaning we cannot always decide what x is for the given set of c[i] and k.<br />
<br />
Hence the problem reduces to checking if k divides L = lcm(c[1], c[2], ..., c[n]). Focus on p, a prime factor of k. Suppose t is the max integer such that p^t | k. What we need to check is if L has at least t power of p. Notice that lcm(a, b) maximises the power of p. On the other hand, gcd(a, b) minimises the power of p. For example a = 2^3 x 3^4 and b = 2^5 x 3^1 then lcm(a, b) = 2^max(3, 5) x 3^max(4,1). On the other hand gcd(a, b) = 2^min(3,5) x 3^min(4,1).<br />
<br />
With this we have the following implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">Gcd</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> a, <span style="color: #333399; font-weight: bold;">int64_t</span> b) {
<span style="color: #008800; font-weight: bold;">if</span> (a<span style="color: #333333;"><</span>b) swap(a,b);
<span style="color: #008800; font-weight: bold;">if</span> (b <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">0</span>) <span style="color: #008800; font-weight: bold;">return</span> a;
<span style="color: #008800; font-weight: bold;">return</span> Gcd(b, a<span style="color: #333333;">%</span>b);
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">Lcm</span>(<span style="color: #333399; font-weight: bold;">int</span> a, <span style="color: #333399; font-weight: bold;">int</span> b) {
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">1LL</span> <span style="color: #333333;">*</span> a <span style="color: #333333;">*</span> b <span style="color: #333333;">/</span> Gcd(a, b);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> n, k;
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>k);
<span style="color: #333399; font-weight: bold;">int</span> c;
<span style="color: #333399; font-weight: bold;">int</span> trail <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>c);
trail <span style="color: #333333;">=</span> Gcd(k, Lcm(trail, c));
}
<span style="color: #008800; font-weight: bold;">if</span> (trail <span style="color: #333333;">==</span> k) printf(<span style="background-color: #fff0f0;">"Yes</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">else</span> printf(<span style="background-color: #fff0f0;">"No</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
On each iteration, 'trail' contains the maximum power of prime factor p of k over c[1], c[2], ..., c[i] (bounded at the actual power of p in k) for each p. Hence Gcd(k, ...) serves the purpose of truncating all prime factors in c[i] that does not matter, and limiting the power of each prime factor of k to not exceed k.Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-90031097218815725352016-07-06T12:21:00.002+08:002016-08-07T11:01:44.533+08:00Codeforces Codeforces Round #359 (Div. 1) - D. Kay and EternityProblem Statement:<br />
<a href="http://codeforces.com/contest/685/problem/D">http://codeforces.com/contest/685/problem/D</a><br />
<br />
Summary:<br />
In an infinite 2D array, there are n < 10^5 cells (x[i], y[i]) with value 1, where -1e9 <= x[i], y[i] <= 1e9. The rest of the cells are 0. For each m = 1 to n, compute the number of squares with dimension k x k (k <= 300), with the property that each of those squares has exactly m non-zero cells in it.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
Let's uniquely define a square as the index (i, j) of its left bottom corner. Imagine that we have a 2D array S such that S[i][j] is the number of non-empty cell in the square (i, j). One way to compute S is as follows: for each non-empty cell (x, y), add 1 to every S[s][t] such that s is in [x-k+1, x] and t is in [y-k+1, y].<br />
<br />
Now the strategy is to make the above operation fast enough. Let's suppose that we have another array freq[s][t] which is initially 0 for all entries. Instead of adding 1 to every S[s][t] in those ranges, we can add 1 to the row x-k+1 in freq for column in range [y-k+1, y], and subtract 1 from the row x+1 in F from column [y-k+1, y]. S is then can be viewed as the cumulative frequency of freq along the column, i.e. S[s][t] = freq[s][t] + freq[s-1][t] + freq[s-2][t] + ... . Hence using this technique, we can transform all (x, y) cells into two queries of the form (row, L, R, val): (x-k+1, y-k+1, y, +1) and (x+1, y-k+1, y, -1) where (row, L, R, val) means perform addition of val to entries in freq[row][L ... R].<br />
<br />
With the concept of cumulative frequency and transformation of the problem space into update queries, we can solve the problem as follows:<br />
1) We will perform a sweeping line over all queries (row, L, R, val) in increasing row.<br />
2) Firstly initialise two arrays last_updated[] and cnt[], where last_updated[i] stores the row of the latest update query performed on column i, while cnt[i] stores the value freq[last_updated[i]][i], the most current frequency value of column i. Also initialise ans[i] which will contain the total number of squares containing i non-empty cells.<br />
3) For each query (row, L, R, val):<br />
Iterate through i = L to R, update ans[cnt[i]] by adding row - last_updated[i] (because all values in S[row-1] to S[last_updated[i]] are equal to cnt[i]). Then update last_updated[i] = row, and update cnt[i] = cnt[i] + val.<br />
<br />
Since we need to sort the queries in increasing row order, and for each query we need to iterate through k values, overall we need O(n log n + nk) time. Furthermore we need O(nk) space to store the corresponding cnt[] and last_updated[] of all possible column ranges that contains at least a valid square.<br />
Below is the implementation of the above solution. (Note that the shrink_to_fit call is needed to pass the memory limit of this problem...)<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <utility></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
constexpr <span style="color: #333399; font-weight: bold;">int</span> N <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">100001</span>;
constexpr <span style="color: #333399; font-weight: bold;">int</span> K <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">301</span>;
<span style="color: #008800; font-weight: bold;">struct</span> Query {
<span style="color: #333399; font-weight: bold;">int</span> row;
<span style="color: #333399; font-weight: bold;">int</span> left;
<span style="color: #333399; font-weight: bold;">int</span> right;
<span style="color: #333399; font-weight: bold;">bool</span> val;
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #008800; font-weight: bold;">operator</span><span style="color: #333333;"><</span>(<span style="color: #008800; font-weight: bold;">const</span> Query<span style="color: #333333;">&</span> other) <span style="color: #008800; font-weight: bold;">const</span> {
<span style="color: #008800; font-weight: bold;">if</span> (row <span style="color: #333333;">==</span> other.row) {
<span style="color: #008800; font-weight: bold;">return</span> left <span style="color: #333333;">==</span> other.left <span style="color: #333333;">?</span> right <span style="color: #333333;"><</span> other.right <span style="color: #333333;">:</span>
left <span style="color: #333333;"><</span> other.left;
}
<span style="color: #008800; font-weight: bold;">return</span> row <span style="color: #333333;"><</span> other.row;
}
};
constexpr <span style="color: #333399; font-weight: bold;">int</span> MIN_INF <span style="color: #333333;">=</span> (<span style="color: #333399; font-weight: bold;">int</span>) <span style="color: #333333;">-</span><span style="color: #6600ee; font-weight: bold;">1e9</span> <span style="color: #333333;">-</span> <span style="color: #0000dd; font-weight: bold;">7</span>;
<span style="color: #333399; font-weight: bold;">int</span> n, k;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> last_updated;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> cnt;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> arr;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> ans;
vector<span style="color: #333333;"><</span>Query<span style="color: #333333;">></span> queries;
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">getIndex</span>(<span style="color: #333399; font-weight: bold;">int</span> val) {
<span style="color: #333399; font-weight: bold;">int</span> lo<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, hi<span style="color: #333333;">=</span>arr.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, mid;
<span style="color: #008800; font-weight: bold;">while</span>(lo<span style="color: #333333;"><=</span>hi){
mid <span style="color: #333333;">=</span> (lo<span style="color: #333333;">+</span>hi)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #008800; font-weight: bold;">if</span> (arr[mid] <span style="color: #333333;"><</span> val) {
lo <span style="color: #333333;">=</span> mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
hi <span style="color: #333333;">=</span> mid<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #008800; font-weight: bold;">return</span> lo;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> x,y;
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>k);
vector<span style="color: #333333;"><</span>pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span>,<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> points;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>x,<span style="color: #333333;">&</span>y);
points.push_back({x,y});
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>k;<span style="color: #333333;">++</span>j){
arr.push_back(points[i].second<span style="color: #333333;">-</span>k<span style="color: #333333;">+</span>j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
}
points.clear();
sort(arr.begin(), arr.end());
<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><</span>arr.size();<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (arr[j] <span style="color: #333333;">==</span> arr[i]) <span style="color: #008800; font-weight: bold;">continue</span>;
arr[<span style="color: #333333;">++</span>j] <span style="color: #333333;">=</span> arr[i];
}
arr.resize(j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #333399; font-weight: bold;">int</span> left <span style="color: #333333;">=</span> getIndex(points[i].second<span style="color: #333333;">-</span>k<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #333399; font-weight: bold;">int</span> right <span style="color: #333333;">=</span> getIndex(points[i].second);
queries.push_back({points[i].first<span style="color: #333333;">-</span>k<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, left, right, <span style="color: #007020;">true</span>});
queries.push_back({points[i].first<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, left, right, <span style="color: #007020;">false</span>});
}
sort(queries.begin(), queries.end());
arr.clear();
arr.shrink_to_fit();
ans.resize(n<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">0</span>);
cnt.resize(j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">0</span>);
last_updated.resize(j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, MIN_INF);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> q<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;q<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>n;<span style="color: #333333;">++</span>q) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>queries[q].left; i <span style="color: #333333;"><=</span> queries[q].right; <span style="color: #333333;">++</span>i){
ans[cnt[i]] <span style="color: #333333;">+=</span> queries[q].row <span style="color: #333333;">-</span> last_updated[i];
last_updated[i] <span style="color: #333333;">=</span> queries[q].row;
cnt[i] <span style="color: #333333;">+=</span> queries[q].val <span style="color: #333333;">?</span> <span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;">:</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
cout <span style="color: #333333;"><<</span> ans[i] <span style="color: #333333;"><<</span> <span style="background-color: #fff0f0;">" "</span>;
}
cout <span style="color: #333333;"><<</span> endl;
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-91718133493039100662016-07-04T07:34:00.000+08:002016-08-07T11:02:05.477+08:00Codeforces Round #359 (Div. 1) - C. Optimal PointProblem Statement:<br />
<a href="http://codeforces.com/contest/685/problem/C">http://codeforces.com/contest/685/problem/C</a><br />
<br />
Summary:<br />
Find the minimum point M (x, y, z) in Z^3 such that the maximum Manhattan distance between M and a set of points {(x[i], y[i], z[i]) in Z^3} of size <= 100000 is the minimum. Manhattan distance between two points (x, y, z) and (a, b, c) is defined as |x-a| + |y-b| + |z-c|. Furthermore, x, y and z is in [-10^18, 10^18].<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
The crazy thing about this problem is that it is solvable using binary search! It is always surprising to learn that such a fundamental technique can be applied in non-obvious ways.<br />
<br />
The binary search idea is this: for a given V, if |x - x[i]| + |y - y[i]| + |z - z[i]| <= V for all i [where (x[i], y[i], z[i]) is a point in the block] is satisfiable for some (x, y, z), then it will also be satisfiable for larger V. Furthermore, if it is not satisfiable for a certain V, then it is also not satisfiable for lower values of V. This monotonic property can be exploited by cutting in the middle of the search space of V and check if we can eliminate the lower half or upper half of the search space depending whether current value of V is satisfiable. If we can check for the satisfiability in O(n) for a given V, we can solve the problem in O(n log V).<br />
<br />
The hard part is now to check for the satisfiability of the inequality. The main observation to tame the absolute terms is to look at the lower dimension |x- a| + |y - b| <= V. If you draw the graph you will notice that the region that satisfies that inequality is inside a square defined by 4 points (a-V, b), (a, b-V), (a+V, b), and (a, b+V). This square also be seen as the area of intersection of 4 half spaces defined by the 4 lines along the sides of the squares. Equipped with this intuition, we can see that for the case of |x-a| + |y-b| + |z-c| <= V, the set of points that satisfy the inequality is nothing more than an octahedron defined by 8 half spaces defined by the sides of the octahedron. We can combine the inequalities for each pair of parallel sides of the octahedron into an inequality, and we can rewrite the original inequality into the following form:<br />
a+b+c-V <= x + y + z <= a+b+c+V and<br />
-a+b+c-V<= -x + y + z <= -a+b+c+V and<br />
a-b+c-V <= x - y + z <= a-b+c+V and<br />
a+b-c-V <= x + y - z <= a+b-c+V.<br />
<br />
If we rewrite A = x+y+z, B = -x+y+z, C = x-y+z, and D = x+y-z, we can rewrite the above as<br />
a+b+c-V <= A <= a+b+c+V and<br />
-a+b+c-V<= B <= -a+b+c+V and<br />
a-b+c-V <= C <= a-b+c+V and<br />
a+b-c-V <= D <= a+b-c+V,<br />
where x = (C+D)/2, y = (B+D)/2, and z = (B+C)/2.<br />
<br />
Using this formulation, we can check for satisfiability in a linear time. First, we iterate through all the points in the block and for each point we update the ranges of A, B, C, and D that can possibly satisfy the original inequality. Eventually we will arrive at a final range of values for each of them. Next we see if the ranges are actually valid, i.e. each of them are non-empty. If any of them are empty, we conclude that the original inequality |x-a| + |y-b| + |z-c| <= V for all (a, b, c) points in the block is not satisfiable. Otherwise, we have to check further. Since A = B+C+D, we must make sure that the minimum and maximum possible value for B+C+D have some intersections with range of values of A. We will be done if x, y, z are allowed to be real number, however since we are working in integer space, we must check further. since x = (C+D)/2 can only be integer if C and D are of the same parity, we must have C = D mod 2. Similarly for y and z, we can conclude that B = C = D mod 2. Furthermore, A will also have the same parity with B, C and D since A = B+C+D = D mod 2. Hence we have two cases, either A, B, C, D are even or odd. For each cases, we check the ranges of A, B, C, and D that is of that parity and see if A and B+C+D intersect. If they intersect, we can conclude that the original inequality is satisfiable.<br />
<br />
Now, since the problem requires as to output a point that could gives us the minimum V, we have to add one more logic. Given the ranges of A, B, C and D that can satisfy the inequality, first pick the smallest possible B, C and D. Then from B to D, we increase its value to maximum possible until we see that B+C+D is larger than or equal to lower bound of A, but not larger than its upper bound. We can then output x, y and z based on the final B, C, and D.<br />
<br />
One thing to note, you may have to perform additional rearrangement and checks in order to avoid arithmetic overflow in the problem. Hence the implementation can get a little bit obscure.<br />
<br />
Implementation:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
constexpr <span style="color: #333399; font-weight: bold;">int64_t</span> MLLONG_MIN <span style="color: #333333;">=</span> <span style="color: #333333;">-</span><span style="color: #6600ee; font-weight: bold;">4e18</span>;
constexpr <span style="color: #333399; font-weight: bold;">int64_t</span> MLLONG_MAX <span style="color: #333333;">=</span> <span style="color: #6600ee; font-weight: bold;">4e18</span>;
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #333399; font-weight: bold;">int64_t</span> a[<span style="color: #0000dd; font-weight: bold;">100010</span>][<span style="color: #0000dd; font-weight: bold;">3</span>];
<span style="color: #333399; font-weight: bold;">int64_t</span> c[<span style="color: #0000dd; font-weight: bold;">4</span>][<span style="color: #0000dd; font-weight: bold;">3</span>] <span style="color: #333333;">=</span> {
{<span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>},
{<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>},
{<span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>},
{<span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #0000dd; font-weight: bold;">1</span>, <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>}
};
<span style="color: #008800; font-weight: bold;">inline</span> <span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">Mod2</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> v) {
<span style="color: #008800; font-weight: bold;">return</span> (v<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">2LL</span> <span style="color: #333333;">+</span> <span style="color: #0000dd; font-weight: bold;">2</span>) <span style="color: #333333;">%</span> <span style="color: #0000dd; font-weight: bold;">2</span>;
}
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">IsSatisfiable</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> v, <span style="color: #333399; font-weight: bold;">bool</span> get_point<span style="color: #333333;">=</span><span style="color: #007020;">false</span>, <span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">*</span> result<span style="color: #333333;">=</span>nullptr) {
<span style="color: #333399; font-weight: bold;">int64_t</span> ranges[<span style="color: #0000dd; font-weight: bold;">4</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">4</span>;<span style="color: #333333;">++</span>i){
ranges[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> MLLONG_MIN;
ranges[i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> MLLONG_MAX;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">4</span>;<span style="color: #333333;">++</span>j){
ranges[j][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> max(ranges[j][<span style="color: #0000dd; font-weight: bold;">0</span>],
c[j][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>c[j][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span>c[j][<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">-</span>v);
ranges[j][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> min(ranges[j][<span style="color: #0000dd; font-weight: bold;">1</span>],
c[j][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>c[j][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span>c[j][<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">*</span>a[i][<span style="color: #0000dd; font-weight: bold;">2</span>]<span style="color: #333333;">+</span>v);
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">4</span>;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (ranges[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">></span> ranges[i][<span style="color: #0000dd; font-weight: bold;">1</span>]) <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> res<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;res<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">2</span>;<span style="color: #333333;">++</span>res){
<span style="color: #333399; font-weight: bold;">int64_t</span> filter[<span style="color: #0000dd; font-weight: bold;">4</span>][<span style="color: #0000dd; font-weight: bold;">2</span>];
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">4</span>;<span style="color: #333333;">++</span>i){
filter[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> MLLONG_MIN;
filter[i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> MLLONG_MAX;
}
<span style="color: #333399; font-weight: bold;">bool</span> is_consistent <span style="color: #333333;">=</span> <span style="color: #007020;">true</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">4</span>;<span style="color: #333333;">++</span>i){
filter[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> max(filter[i][<span style="color: #0000dd; font-weight: bold;">0</span>], Mod2(ranges[i][<span style="color: #0000dd; font-weight: bold;">0</span>]) <span style="color: #333333;">==</span> res <span style="color: #333333;">?</span> ranges[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">:</span> ranges[i][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
filter[i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> min(filter[i][<span style="color: #0000dd; font-weight: bold;">1</span>], Mod2(ranges[i][<span style="color: #0000dd; font-weight: bold;">1</span>]) <span style="color: #333333;">==</span> res <span style="color: #333333;">?</span> ranges[i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">:</span> ranges[i][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
<span style="color: #008800; font-weight: bold;">if</span> (filter[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">></span> filter[i][<span style="color: #0000dd; font-weight: bold;">1</span>]) {
is_consistent <span style="color: #333333;">=</span> <span style="color: #007020;">false</span>;
<span style="color: #008800; font-weight: bold;">break</span>;
}
}
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>is_consistent) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #008800; font-weight: bold;">if</span> (filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">-</span>filter[<span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;"><</span>filter[<span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>filter[<span style="color: #0000dd; font-weight: bold;">3</span>][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">||</span>
filter[<span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span>filter[<span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;"><</span>filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">-</span>filter[<span style="color: #0000dd; font-weight: bold;">3</span>][<span style="color: #0000dd; font-weight: bold;">1</span>]) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #008800; font-weight: bold;">if</span> (get_point) {
<span style="color: #333399; font-weight: bold;">int64_t</span> sum <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> point_out[<span style="color: #0000dd; font-weight: bold;">3</span>];
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">3</span>;<span style="color: #333333;">++</span>i){
point_out[i] <span style="color: #333333;">=</span> filter[i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">0</span>];
sum <span style="color: #333333;">+=</span> point_out[i];
}
<span style="color: #008800; font-weight: bold;">if</span> (filter[<span style="color: #0000dd; font-weight: bold;">2</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>filter[<span style="color: #0000dd; font-weight: bold;">3</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">>=</span>filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">-</span>filter[<span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]) {
result[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">2</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
result[<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">2</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
result[<span style="color: #0000dd; font-weight: bold;">2</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">1</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">3</span>;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (sum <span style="color: #333333;">>=</span> filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">0</span>]) <span style="color: #008800; font-weight: bold;">break</span>;
sum <span style="color: #333333;">-=</span> point_out[i];
<span style="color: #008800; font-weight: bold;">if</span> (sum <span style="color: #333333;">></span> filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">-</span> filter[i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">1</span>]) {
<span style="color: #333399; font-weight: bold;">int64_t</span> X <span style="color: #333333;">=</span> filter[<span style="color: #0000dd; font-weight: bold;">0</span>][<span style="color: #0000dd; font-weight: bold;">1</span>];
<span style="color: #008800; font-weight: bold;">if</span> (Mod2(X) <span style="color: #333333;">!=</span> (Mod2(filter[i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">0</span>])<span style="color: #333333;">+</span>Mod2(sum))<span style="color: #333333;">%</span><span style="color: #0000dd; font-weight: bold;">2</span>) {
X<span style="color: #333333;">--</span>;
}
point_out[i] <span style="color: #333333;">=</span> X<span style="color: #333333;">-</span>sum;
sum <span style="color: #333333;">=</span> X;
<span style="color: #008800; font-weight: bold;">break</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
point_out[i] <span style="color: #333333;">=</span> filter[i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>][<span style="color: #0000dd; font-weight: bold;">1</span>];
sum <span style="color: #333333;">+=</span> point_out[i];
}
}
result[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">2</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
result[<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">2</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
result[<span style="color: #0000dd; font-weight: bold;">2</span>] <span style="color: #333333;">=</span> (point_out[<span style="color: #0000dd; font-weight: bold;">0</span>]<span style="color: #333333;">+</span>point_out[<span style="color: #0000dd; font-weight: bold;">1</span>])<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">true</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #007020;">false</span>;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Solve</span>() {
<span style="color: #333399; font-weight: bold;">int64_t</span> lo<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, hi<span style="color: #333333;">=</span><span style="color: #6600ee; font-weight: bold;">4e18</span>, mid;
<span style="color: #008800; font-weight: bold;">while</span> (lo<span style="color: #333333;"><=</span>hi){
mid <span style="color: #333333;">=</span> lo <span style="color: #333333;">+</span> (hi<span style="color: #333333;">-</span>lo)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2LL</span>;
<span style="color: #008800; font-weight: bold;">if</span> (IsSatisfiable(mid)) {
hi<span style="color: #333333;">=</span>mid<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1LL</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
lo<span style="color: #333333;">=</span>mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1LL</span>;
}
}
<span style="color: #333399; font-weight: bold;">int64_t</span> ans[<span style="color: #0000dd; font-weight: bold;">3</span>];
IsSatisfiable(lo, <span style="color: #007020;">true</span>, ans);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">3</span>;<span style="color: #333333;">++</span>i){
cout <span style="color: #333333;"><<</span> ans[i] <span style="color: #333333;"><<</span> <span style="background-color: #fff0f0;">" "</span>;
}
cout <span style="color: #333333;"><<</span> endl;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> tc;
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>tc);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> t<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;t<span style="color: #333333;"><</span>tc;<span style="color: #333333;">++</span>t){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
cin <span style="color: #333333;">>></span> a[i][<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">>></span> a[i][<span style="color: #0000dd; font-weight: bold;">1</span>] <span style="color: #333333;">>></span> a[i][<span style="color: #0000dd; font-weight: bold;">2</span>];
}
Solve();
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-18516989105468137402016-07-03T11:48:00.000+08:002016-08-07T11:02:25.612+08:00Codeforces Round #359 (Div. 2) - D. Kay and SnowflakeProblem Statement:<br />
<a href="http://codeforces.com/contest/686/problem/D">http://codeforces.com/contest/686/problem/D</a><br />
<br />
Summary:<br />
Given a tree of size n <= 300000, answer q <= 300000 queries of the form: find the centroid of subtree v. Centroid of subtree T is defined as a node in T such that when removed the resulting set of disjoint trees have sizes at most |T|/2 (half the size of initial subtree).<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
Focus on a tree T and try to locate the centroid. The centroid of T must be the root of a subtree S that with size |S| >= |T|/2 (because otherwise, if S has size < |T|/2, then the remaining connected component must have size |T| - |S| >= |T|/2). Starting from root of T, by following the path of the largest child down the tree, we will reach S (on each node on this path, there will exactly be one child with size >= |T|/2). Furthermore, by definition, children of S must have sizes less than |T|/2, hence S is the smallest subtree in this path with size >= |T|/2.<br />
<br />
Based on above observation, we can come up with a linear solution in n and q. First we compute the centroid for every subtree, and then we answer the queries. We will employ a simple recursive solution to compute a centroid of subtree rooted at u, call it T(u). For each child of u, compute its centroid. Then take note of the largest child v. We know the centroid of v, say w. Let's iterate through the path from w to u, starting from w, and check if current node has size >= |T(u)|/2. If so, we have found the centroid of u! If not, we one step up the path (i.e. go to the parent of current node). Note that it is possible that u is the only node that has size >= |T(u)|/2, which means that u is the centroid of its own subtree. If we proceed this computation in bottom up order, the whole recursion will take O(n) time (This is because the centroid of a tree cannot be lower than the centroid of its subtrees, hence when we consider the path w-v-u, the nodes that we have visited will not be visited more than once up the recursion tree).<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
vector<span style="color: #333333;"><</span>vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> adj;
<span style="color: #333399; font-weight: bold;">int</span> n, q;
<span style="color: #333399; font-weight: bold;">int</span> par[<span style="color: #0000dd; font-weight: bold;">300010</span>];
<span style="color: #333399; font-weight: bold;">int</span> sz[<span style="color: #0000dd; font-weight: bold;">300010</span>], centroid[<span style="color: #0000dd; font-weight: bold;">300010</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ComputeSize</span>(<span style="color: #333399; font-weight: bold;">int</span> u) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>adj[u].size();<span style="color: #333333;">++</span>i){
ComputeSize(adj[u][i]);
sz[u] <span style="color: #333333;">+=</span> sz[adj[u][i]];
}
sz[u]<span style="color: #333333;">++</span>;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ComputeCentroid</span>(<span style="color: #333399; font-weight: bold;">int</span> u) {
<span style="color: #008800; font-weight: bold;">if</span> (sz[u]<span style="color: #333333;">==</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
centroid[u] <span style="color: #333333;">=</span> u;
<span style="color: #008800; font-weight: bold;">return</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> largest <span style="color: #333333;">=</span> adj[u][<span style="color: #0000dd; font-weight: bold;">0</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>adj[u].size();<span style="color: #333333;">++</span>i){
<span style="color: #333399; font-weight: bold;">int</span> v <span style="color: #333333;">=</span> adj[u][i];
ComputeCentroid(v);
largest <span style="color: #333333;">=</span> sz[largest] <span style="color: #333333;"><</span> sz[v] <span style="color: #333333;">?</span> v <span style="color: #333333;">:</span> largest;
}
<span style="color: #333399; font-weight: bold;">int</span> half <span style="color: #333333;">=</span> sz[u] <span style="color: #333333;">-</span> sz[u]<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #333399; font-weight: bold;">int</span> cur <span style="color: #333333;">=</span> centroid[largest];
<span style="color: #008800; font-weight: bold;">while</span> (cur <span style="color: #333333;">!=</span> u) {
<span style="color: #008800; font-weight: bold;">if</span> (sz[cur] <span style="color: #333333;"><</span> half) {
cur <span style="color: #333333;">=</span> par[cur];
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">break</span>;
}
centroid[u] <span style="color: #333333;">=</span> cur;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>() {
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>q);
adj.resize(n<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">2</span>);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>par[i]);
par[i]<span style="color: #333333;">--</span>;
adj[par[i]].push_back(i);
}
par[<span style="color: #0000dd; font-weight: bold;">0</span>] <span style="color: #333333;">=</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
ComputeSize(<span style="color: #0000dd; font-weight: bold;">0</span>);
ComputeCentroid(<span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #333399; font-weight: bold;">int</span> u;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>q;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>u);
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,centroid[u<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>]<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-18564949433397374492016-06-26T08:02:00.000+08:002016-08-07T11:02:48.714+08:00Codeforces 455E - FunctionProblem Statement:<br />
<a href="http://codeforces.com/contest/455/problem/E">http://codeforces.com/contest/455/problem/E</a><br />
<br />
Summary:<br />
Given a function f(i, j) = min (f(i-1, j), f(i-1, j-1)) + a[j], where f(1, j) = a[j], and m queries (m <= 10^5) in the form (i, j), compute f(i, j) of each queries.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
This problem employs similar technique as in problem <a href="http://codeforces.com/contest/678/problem/F">http://codeforces.com/contest/678/problem/F</a>, as one of the contestants pointed out. The interesting part is that at first glance the problem feels more like a DP problem than a convex hull problem.<br />
<br />
Play with the recursive function a little bit, and you will see that the function actually tries to find the minimum over all possible a[j]*c[j] + a[j-1]*c[j-1] + ... + a[j-i+1] * c[j-i+1] where each c[k] >= 1, and sum of c[k] = i. Drawing a tree out of the recursive function will show you this relationship clearly.<br />
<br />
The key observation is that, if we fix the segment [k, j], such that we must use elements a[k], a[k+1], ..., a[j] and try to minimise a[k] * c[k] + ... + a[j] * c[j], the strategy is naturally to find a[m] the smallest element in a[k..j] and set c[m] the highest possible values, while the rest of c[i] is set to 1, for all i in [k, j] excluding m. If we already computed a prefix sum of a[1..n], we can compute the minimum sum in segment [k...j] as sum[j] - sum[k] + a[m] * (i - (j - k)).<br />
<br />
Furthermore, if the smallest element c[m] is not c[k], then we know that the minimum value obtained in segment [m...j] is smaller than that of [k...j]. Hence we can reformulate f(i, j) as follows:<br />
f(i, j) = min{ sum[j] - sum[k] + a[k] * (i - (j-k)) } for all k in [j-i+1, j].<br />
Since sum[j] does not depend on k, we can take it out of the min{}, and by regrouping the elements with term k together we get<br />
f(i, j) = sum[j] + min{ a[k] * (i-j) + a[k]*k - sum[k] } over k.<br />
By setting G(k, X) = m*X + c where m = a[k] and c = a[k]*k - sum[k], we can represent f(i, j) as finding the minimum intersection between lines G(k, X) for all k in [j-i+1, j] and X = (i-j). Now this is similar to problem 678F!<br />
<br />
By applying the convex-hull construction over linear functions, we can solve the above problem. Construction of the convex-hull is simply done by first sorting the lines in terms of decreasing gradient m (and decreasing c to break ties), and iterating over the lines by maintaining a stack of lines S. For each new line L to consider, we see if the intersection between L and S.top() is ahead of (or larger than) the intersection between top two lines on S. If so, we can add L to S. Otherwise pop S once and repeat. In the end S will contain the desired convex hull. Then we can binary search the convex hull for each value of X in O(lg S) to compute the minimum of intersection between x = X and all the original lines.<br />
<br />
The problem is slightly more complicated in the sense that for each query (i, j), we must only consider the lines in [j-i+1, j]. Turns out, by marrying segment tree with the above convex hull construction, we can build a segment tree of convex hulls in O(N lg N) time, and we can answer the queries in O(lg N) * O(lg N) time (since for each query, we must traverse the segment tree in O(lg N) time to find the desired segments, and on each segment we perform a binary search over the convex hull in O(lg N) time). The construction of the segment tree can be done in O(N lg N) time by sorting the lines once before segment tree construction, and performing a "bucketing" over lines currently considered in segment [L, R] by grouping the lines into segment [L, M] and [M+1, R] while maintaining the relative ordering of elements in each bucket (similar to the idea of radix sort / bucketing sorted elements such that the elements in each bucket is still sorted).<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <queue></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #008800; font-weight: bold;">const</span> <span style="color: #333399; font-weight: bold;">int64_t</span> MAX_INF <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;"><<</span><span style="color: #0000dd; font-weight: bold;">61</span>;
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">Line</span> {
<span style="color: #997700; font-weight: bold;">public:</span>
Line(<span style="color: #333399; font-weight: bold;">int64_t</span> m, <span style="color: #333399; font-weight: bold;">int64_t</span> c, <span style="color: #333399; font-weight: bold;">int</span> id) <span style="color: #333333;">:</span> m_(m), c_(c), id_(id) {}
<span style="color: #333399; font-weight: bold;">bool</span> IsParallel(<span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> other) {
<span style="color: #008800; font-weight: bold;">return</span> other.m_ <span style="color: #333333;">==</span> m_;
}
<span style="color: #333399; font-weight: bold;">bool</span> IsIncreasing(<span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_1, <span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_2) {
<span style="color: #008800; font-weight: bold;">return</span> (line_1.c_<span style="color: #333333;">-</span>c_)<span style="color: #333333;">*</span>(line_1.m_<span style="color: #333333;">-</span>line_2.m_) <span style="color: #333333;"><</span>
(line_2.c_<span style="color: #333333;">-</span>line_1.c_)<span style="color: #333333;">*</span>(m_<span style="color: #333333;">-</span>line_1.m_);
}
<span style="color: #333399; font-weight: bold;">int64_t</span> At(<span style="color: #333399; font-weight: bold;">int64_t</span> x) {
<span style="color: #008800; font-weight: bold;">return</span> x<span style="color: #333333;">*</span>m_ <span style="color: #333333;">+</span> c_;
}
<span style="color: #333399; font-weight: bold;">int64_t</span> m_;
<span style="color: #333399; font-weight: bold;">int64_t</span> c_;
<span style="color: #333399; font-weight: bold;">int</span> id_;
};
<span style="color: #333399; font-weight: bold;">bool</span> <span style="color: #0066bb; font-weight: bold;">IsOverIntersection</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> x, <span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_1, <span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_2) {
<span style="color: #008800; font-weight: bold;">return</span> line_2.c_<span style="color: #333333;">-</span>line_1.c_ <span style="color: #333333;"><</span> (line_1.m_<span style="color: #333333;">-</span>line_2.m_)<span style="color: #333333;">*</span>x;
}
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">ConvexHull</span> {
<span style="color: #997700; font-weight: bold;">public:</span>
<span style="color: #333399; font-weight: bold;">void</span> Construct(<span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">>&</span> lines) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>lines.size();<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>hull_.empty()) {
<span style="color: #008800; font-weight: bold;">if</span> (hull_.back().IsParallel(lines[i])) {
hull_.pop_back();
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (hull_.size() <span style="color: #333333;">></span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
Line<span style="color: #333333;">&</span> line_1 <span style="color: #333333;">=</span> hull_[hull_.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">2</span>];
Line<span style="color: #333333;">&</span> line_2 <span style="color: #333333;">=</span> hull_.back();
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>line_1.IsIncreasing(line_2, lines[i])) {
hull_.pop_back();
<span style="color: #008800; font-weight: bold;">continue</span>;
}
}
<span style="color: #008800; font-weight: bold;">break</span>;
}
hull_.push_back(lines[i]);
}
}
<span style="color: #333399; font-weight: bold;">int64_t</span> BinarySearch(<span style="color: #333399; font-weight: bold;">int64_t</span> x) {
<span style="color: #333399; font-weight: bold;">int</span> lo<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>, hi<span style="color: #333333;">=</span>hull_.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, mid;
<span style="color: #008800; font-weight: bold;">while</span> (lo <span style="color: #333333;"><=</span> hi) {
mid <span style="color: #333333;">=</span> (lo<span style="color: #333333;">+</span>hi)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #008800; font-weight: bold;">if</span> (mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;"><</span> hull_.size()) {
<span style="color: #008800; font-weight: bold;">if</span> (IsOverIntersection(x, hull_[mid], hull_[mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>])) {
lo <span style="color: #333333;">=</span> mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
hi <span style="color: #333333;">=</span> mid<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">break</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> hull_[lo].At(x);
}
vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">></span> hull_;
};
<span style="color: #008800; font-weight: bold;">class</span> <span style="color: #bb0066; font-weight: bold;">SegmentTree</span> {
<span style="color: #997700; font-weight: bold;">public:</span>
<span style="color: #008800; font-weight: bold;">struct</span> Node {
<span style="color: #333399; font-weight: bold;">int</span> L; <span style="color: #333399; font-weight: bold;">int</span> R; <span style="color: #333399; font-weight: bold;">int</span> p;
};
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Init</span>(<span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">>&</span> lines) {
<span style="color: #888888;">// 'lines' is sorted in (m, c) order.</span>
n_ <span style="color: #333333;">=</span> lines.size();
tree.clear();
tree.resize(<span style="color: #0000dd; font-weight: bold;">4</span><span style="color: #333333;">*</span>n_);
Build(lines, <span style="color: #0000dd; font-weight: bold;">1</span>, n_, <span style="color: #0000dd; font-weight: bold;">1</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Build</span>(<span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">>&</span> lines, <span style="color: #333399; font-weight: bold;">int</span> L, <span style="color: #333399; font-weight: bold;">int</span> R, <span style="color: #333399; font-weight: bold;">int</span> p) {
<span style="color: #008800; font-weight: bold;">if</span> (L<span style="color: #333333;">></span>R) <span style="color: #008800; font-weight: bold;">return</span>;
tree[p].Construct(lines);
<span style="color: #008800; font-weight: bold;">if</span> (L<span style="color: #333333;">==</span>R) <span style="color: #008800; font-weight: bold;">return</span>;
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (L<span style="color: #333333;">+</span>R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">></span> left_lines, right_lines;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>lines.size();<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (lines[i].id_ <span style="color: #333333;"><=</span> M) {
left_lines.push_back(lines[i]);
} <span style="color: #008800; font-weight: bold;">else</span> {
right_lines.push_back(lines[i]);
}
}
Build(left_lines, L, M, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p);
Build(right_lines, M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, R, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
<span style="color: #333399; font-weight: bold;">int64_t</span> <span style="color: #0066bb; font-weight: bold;">Rmq</span>(<span style="color: #333399; font-weight: bold;">int</span> S, <span style="color: #333399; font-weight: bold;">int</span> T, <span style="color: #333399; font-weight: bold;">int64_t</span> x) {
<span style="color: #333399; font-weight: bold;">int64_t</span> ret <span style="color: #333333;">=</span> MAX_INF;
queue<span style="color: #333333;"><</span>Node<span style="color: #333333;">></span> nodes;
nodes.push({<span style="color: #0000dd; font-weight: bold;">1</span>, n_, <span style="color: #0000dd; font-weight: bold;">1</span>});
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>nodes.empty()) {
Node t <span style="color: #333333;">=</span> nodes.front();
nodes.pop();
<span style="color: #008800; font-weight: bold;">if</span> (T <span style="color: #333333;"><</span> t.L <span style="color: #333333;">||</span> t.R <span style="color: #333333;"><</span> S) {
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (S <span style="color: #333333;"><=</span> t.L <span style="color: #333333;">&&</span> t.R <span style="color: #333333;"><=</span> T) {
ret <span style="color: #333333;">=</span> min(ret, tree[t.p].BinarySearch(x));
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #333399; font-weight: bold;">int</span> M <span style="color: #333333;">=</span> (t.L<span style="color: #333333;">+</span>t.R)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
nodes.push({t.L, M, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>t.p});
nodes.push({M<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>, t.R, <span style="color: #0000dd; font-weight: bold;">2</span><span style="color: #333333;">*</span>t.p<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>});
}
<span style="color: #008800; font-weight: bold;">return</span> ret;
}
<span style="color: #333399; font-weight: bold;">int</span> n_;
vector<span style="color: #333333;"><</span>ConvexHull<span style="color: #333333;">></span> tree;
};
<span style="color: #333399; font-weight: bold;">int</span> n, m;
<span style="color: #333399; font-weight: bold;">int</span> a[<span style="color: #0000dd; font-weight: bold;">100010</span>];
<span style="color: #333399; font-weight: bold;">int64_t</span> sum[<span style="color: #0000dd; font-weight: bold;">100010</span>];
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
vector<span style="color: #333333;"><</span>Line<span style="color: #333333;">></span> lines;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;i<span style="color: #333333;"><=</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a[i]);
sum[i] <span style="color: #333333;">=</span> a[i];
<span style="color: #008800; font-weight: bold;">if</span> (i<span style="color: #333333;">></span><span style="color: #0000dd; font-weight: bold;">1</span>) sum[i] <span style="color: #333333;">+=</span> sum[i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>];
lines.push_back({a[i], <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>a[i]<span style="color: #333333;">*</span>i<span style="color: #333333;">-</span>sum[i], i});
}
sort(lines.begin(), lines.end(),
[](<span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_1, <span style="color: #008800; font-weight: bold;">const</span> Line<span style="color: #333333;">&</span> line_2) {
<span style="color: #008800; font-weight: bold;">if</span> (line_1.m_ <span style="color: #333333;">==</span> line_2.m_) <span style="color: #008800; font-weight: bold;">return</span> line_1.c_ <span style="color: #333333;">></span> line_2.c_;
<span style="color: #008800; font-weight: bold;">return</span> line_1.m_ <span style="color: #333333;">></span> line_2.m_;
});
SegmentTree tree;
tree.Init(lines);
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>m);
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> q<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;q<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>q){
<span style="color: #333399; font-weight: bold;">int</span> i,j;
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>i, <span style="color: #333333;">&</span>j);
cout <span style="color: #333333;"><<</span> sum[j] <span style="color: #333333;">+</span> tree.Rmq(min(max(<span style="color: #0000dd; font-weight: bold;">0</span>,j<span style="color: #333333;">-</span>i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>), n), j, i<span style="color: #333333;">-</span>j) <span style="color: #333333;"><<</span> endl;;
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-55057774910041155712016-06-22T15:47:00.001+08:002016-08-07T11:03:11.082+08:00Codeforces 678F - Lena and QueriesProblem Statement:<br />
<a href="http://codeforces.com/contest/678/problem/F">http://codeforces.com/contest/678/problem/F</a><br />
<br />
Summary:<br />
There are n <= 300000 queries of the form: add lines ax+b, remove line ax+b, and the maximum intersection between vertical line x = q and all lines.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
This problem can be solved by partitioning the queries into sqrt(n) blocks. Proceed from first block of queries to the last. We will answer each of query of the third type in O(sqrt(N) + log(N)).<br />
<br />
Suppose we are currently processing block i. In current block, find all the queries of second type where we delete a line from previous blocks. The idea is to move these deleted lines into current block, as if we have created it in this current block i.<br />
<br />
Next we iterate through all lines created in the previous blocks 1, 2, .., i-1, which has not been deleted in block i, and build a "convex-hull" like structure where we keep track of the top lines and the intersection points of those top lines. (What I mean by top lines are, if you draw several linear lines and trace the highest intersection with every vertical lines x = q, you will get segments of top lines).<br />
<br />
This can be done by going through the lines in sorted order (in increasing gradient a, and followed by increasing b to break ties). Keep a stack of lines S. For each line L, we pop the stack until we find the case where the intersection between S.top() and L is in front of the intersection between the two lines on the top of S. S will in the end define the convex-hull structure, where all lines in S are top lines for various values of x. This construction takes O(N).<br />
<br />
To answer the queries of the third type in current block i, we first collect and sort those queries. Since there are at most sqrt(N) of them in current block, sorting will take O(sqrt(N) log (N)). Then we go through the convex-hull structure from left to right, iterating through the top lines one by one and if current query is on the line, we can compute aq+b for that query and move on. Iterating two sorted lists in this fashion takes O(N).<br />
<br />
However for each query we also need to compare the result from the convex-hull with all the lines in the current block. Since there are at most sqrt(N) lines in current block, we can iterate through them one by one and compute the max aq+b among the lines in the current block in O(sqrt(N)). Deletion can also be handled in O(1) by using a flag array. Hence overall in the current block we will perform O(N + sqrt(N) log (N)) operations. Overall, since there are O(sqrt(N)) blocks, the run time complexity is O(N sqrt(N) + N log N).<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <utility></span>
<span style="color: #557799;">#include <map></span>
<span style="color: #557799;">#include <cmath></span>
<span style="color: #557799;">#include <cstring></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
constexpr <span style="color: #333399; font-weight: bold;">int</span> N <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">300010</span>;
constexpr <span style="color: #333399; font-weight: bold;">int64_t</span> MIN_INF <span style="color: #333333;">=</span> <span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1234567891234567891LL</span>;
<span style="color: #008800; font-weight: bold;">struct</span> Request {
<span style="color: #333399; font-weight: bold;">int</span> type;
<span style="color: #333399; font-weight: bold;">int</span> key;
};
<span style="color: #333399; font-weight: bold;">int</span> n, num_lines, num_reqs, sz;
pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span>,<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> lines[N];
Request requests[N];
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> sstable;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> sstable_index;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">SortLines</span>() {
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>num_lines;<span style="color: #333333;">++</span>i){
sstable.push_back(i);
}
sort(sstable.begin(), sstable.end(),
[](<span style="color: #333399; font-weight: bold;">int</span> i, <span style="color: #333399; font-weight: bold;">int</span> j) {
<span style="color: #008800; font-weight: bold;">if</span> (lines[i].first <span style="color: #333333;">==</span> lines[j].first) {
<span style="color: #008800; font-weight: bold;">return</span> lines[i].second <span style="color: #333333;"><</span> lines[j].second;
}
<span style="color: #008800; font-weight: bold;">return</span> lines[i].first <span style="color: #333333;"><</span> lines[j].first;
});
sstable_index.resize(num_lines,<span style="color: #0000dd; font-weight: bold;">0</span>);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>num_lines;<span style="color: #333333;">++</span>i){
sstable_index[sstable[i]]<span style="color: #333333;">=</span>i;
}
}
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> cur_block;
<span style="color: #333399; font-weight: bold;">int</span> in_block[N];
<span style="color: #333399; font-weight: bold;">int</span> in_hull[N];
vector<span style="color: #333333;"><</span>pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span>,<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> queries;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> convex_hull;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> final_ans;
<span style="color: #333399; font-weight: bold;">int</span> num_query<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> block_cnt<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ProcessQueries</span>(<span style="color: #333399; font-weight: bold;">int</span> beg, <span style="color: #333399; font-weight: bold;">int</span> end) {
<span style="color: #333333;">++</span>block_cnt;
cur_block.clear();
queries.clear();
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>beg;i<span style="color: #333333;"><=</span>end;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (requests[i].type <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">2</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (requests[i].key <span style="color: #333333;">>=</span> beg) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #333399; font-weight: bold;">int</span> key <span style="color: #333333;">=</span> requests[i].key;
in_block[requests[key].key] <span style="color: #333333;">=</span> block_cnt;
in_hull[sstable_index[requests[key].key]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
cur_block.push_back(requests[key].key);
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span> (requests[i].type <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">3</span>) {
queries.push_back({requests[i].key, final_ans.size()});
final_ans.push_back(MIN_INF);
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>beg<span style="color: #333333;">-</span>sz;i<span style="color: #333333;"><</span>beg;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (requests[i].type <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">if</span> (in_block[requests[i].key] <span style="color: #333333;">==</span> block_cnt) <span style="color: #008800; font-weight: bold;">continue</span>;
in_hull[sstable_index[requests[i].key]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span> (requests[i].type <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">2</span>) {
<span style="color: #333399; font-weight: bold;">int</span> key <span style="color: #333333;">=</span> requests[i].key;
in_hull[sstable_index[requests[key].key]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
}
convex_hull.clear();
<span style="color: #333399; font-weight: bold;">int</span> a,b,a1,a2,b1,b2;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>num_lines; <span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>in_hull[i]) <span style="color: #008800; font-weight: bold;">continue</span>;
a <span style="color: #333333;">=</span> lines[sstable[i]].first;
b <span style="color: #333333;">=</span> lines[sstable[i]].second;
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #333333;">!</span>convex_hull.empty()) {
a1 <span style="color: #333333;">=</span> lines[convex_hull.back()].first;
b1 <span style="color: #333333;">=</span> lines[convex_hull.back()].second;
<span style="color: #008800; font-weight: bold;">if</span> (a <span style="color: #333333;">==</span> a1) {
convex_hull.pop_back();
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #008800; font-weight: bold;">if</span> (convex_hull.size() <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
<span style="color: #008800; font-weight: bold;">break</span>;
}
a2 <span style="color: #333333;">=</span> lines[convex_hull[convex_hull.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">2</span>]].first;
b2 <span style="color: #333333;">=</span> lines[convex_hull[convex_hull.size()<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">2</span>]].second;
<span style="color: #008800; font-weight: bold;">if</span> ((<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>b1<span style="color: #333333;">-</span>b2)<span style="color: #333333;">*</span>(<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>a1<span style="color: #333333;">-</span>a) <span style="color: #333333;"><</span> (<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>a2<span style="color: #333333;">-</span>a1)<span style="color: #333333;">*</span>(<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>b<span style="color: #333333;">-</span>b1)) <span style="color: #008800; font-weight: bold;">break</span>;
convex_hull.pop_back();
}
convex_hull.push_back(sstable[i]);
}
sort(queries.begin(), queries.end());
<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>queries.size() <span style="color: #333333;">&&</span> <span style="color: #333333;">!</span>convex_hull.empty();<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">while</span> (<span style="color: #0000dd; font-weight: bold;">1</span>) {
a <span style="color: #333333;">=</span> lines[convex_hull[j]].first;
b <span style="color: #333333;">=</span> lines[convex_hull[j]].second;
<span style="color: #008800; font-weight: bold;">if</span> (j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span> <span style="color: #333333;"><</span> convex_hull.size()) {
<span style="color: #333399; font-weight: bold;">int</span> a1 <span style="color: #333333;">=</span> lines[convex_hull[j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>]].first;
<span style="color: #333399; font-weight: bold;">int</span> b1 <span style="color: #333333;">=</span> lines[convex_hull[j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>]].second;
<span style="color: #008800; font-weight: bold;">if</span> ((<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>b<span style="color: #333333;">-</span>b1)<span style="color: #333333;">>=</span>(<span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>a1<span style="color: #333333;">-</span>a)<span style="color: #333333;">*</span>queries[i].first) {
<span style="color: #008800; font-weight: bold;">break</span>;
}
<span style="color: #333333;">++</span>j;
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">break</span>;
}
final_ans[queries[i].second] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>a<span style="color: #333333;">*</span>queries[i].first<span style="color: #333333;">+</span>b;
}
<span style="color: #333399; font-weight: bold;">int</span> num_deleted <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>beg;i<span style="color: #333333;"><=</span>end;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (requests[i].type<span style="color: #333333;">==</span><span style="color: #0000dd; font-weight: bold;">1</span>) {
cur_block.push_back(requests[i].key);
in_block[requests[i].key]<span style="color: #333333;">=</span>block_cnt;
} <span style="color: #008800; font-weight: bold;">else</span> <span style="color: #008800; font-weight: bold;">if</span> (requests[i].type<span style="color: #333333;">==</span><span style="color: #0000dd; font-weight: bold;">2</span>) {
<span style="color: #333399; font-weight: bold;">int</span> key <span style="color: #333333;">=</span> requests[i].key;
in_block[requests[key].key]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333333;">++</span>num_deleted;
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #008800; font-weight: bold;">if</span> (cur_block.size() <span style="color: #333333;">==</span> num_deleted) {
<span style="color: #333333;">++</span>num_query;
<span style="color: #008800; font-weight: bold;">continue</span>;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>cur_block.size();<span style="color: #333333;">++</span>j){
<span style="color: #008800; font-weight: bold;">if</span> (in_block[cur_block[j]] <span style="color: #333333;">!=</span> block_cnt) <span style="color: #008800; font-weight: bold;">continue</span>;
final_ans[num_query] <span style="color: #333333;">=</span> max(final_ans[num_query], <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>requests[i].key<span style="color: #333333;">*</span>lines[cur_block[j]].first<span style="color: #333333;">+</span>lines[cur_block[j]].second);
}
<span style="color: #333333;">++</span>num_query;
}
}
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Solve</span>() {
sz <span style="color: #333333;">=</span> sqrt(n);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;i<span style="color: #333333;">+=</span>sz){
ProcessQueries(i, min(i<span style="color: #333333;">+</span>sz<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>,n<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>));
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>n);
<span style="color: #333399; font-weight: bold;">int</span> t,a,b;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>t);
<span style="color: #008800; font-weight: bold;">if</span> (t <span style="color: #333333;">==</span> <span style="color: #0000dd; font-weight: bold;">1</span>) {
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>a,<span style="color: #333333;">&</span>b);
lines[num_lines<span style="color: #333333;">++</span>] <span style="color: #333333;">=</span> {a,b};
requests[num_reqs<span style="color: #333333;">++</span>] <span style="color: #333333;">=</span> {t, num_lines<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>};
} <span style="color: #008800; font-weight: bold;">else</span> {
scanf(<span style="background-color: #fff0f0;">"%d"</span>,<span style="color: #333333;">&</span>a);
<span style="color: #008800; font-weight: bold;">if</span> (t<span style="color: #333333;">==</span><span style="color: #0000dd; font-weight: bold;">2</span>) {
requests[num_reqs<span style="color: #333333;">++</span>] <span style="color: #333333;">=</span> {t, a<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>};
} <span style="color: #008800; font-weight: bold;">else</span> {
requests[num_reqs<span style="color: #333333;">++</span>] <span style="color: #333333;">=</span> {t, a};
}
}
}
SortLines();
Solve();
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>final_ans.size();<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (final_ans[i] <span style="color: #333333;">==</span> MIN_INF) printf(<span style="background-color: #fff0f0;">"EMPTY SET</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>);
<span style="color: #008800; font-weight: bold;">else</span> printf(<span style="background-color: #fff0f0;">"%I64d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>, final_ans[i]);
}
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
Observation: Sometimes the act of partitioning queries/data into chunks (of sqrt(N) in size for example) can result in an interesting solution with cool time complexity.<br />
<br />
Note: Apparently it is possible to solve this problem using a segment tree, which is way shorter and way faster than the above approach.Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-30673163333246788432016-06-18T12:54:00.000+08:002016-08-07T11:03:29.406+08:00Codeforces Round #356 (Div. 1) - D. Bear and ChaseProblem Statement:<br />
<a href="http://codeforces.com/contest/679/problem/D">Codeforces Round #356 (Div. 1) - D. Bear and Chase</a><br />
<br />
Summary:<br />
We are to maximise the probability of guessing the position of a target in an undirected graph, given that the procedure that we must follow is:<br />
Step 1. Choose a node. The shortest distance to the target is revealed. We either guess where the target is, or go to step 2.<br />
Step 2. Target moves to another node via an edge. Now choose a node again and the shortest distance to the target is revealed. Guess where the target is.<br />
Initially each node has equal probability of containing the target. After Step 1, target moves to a neighbouring node with equal probability among the neighbours.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
Check out the cool editorial: <a href="http://codeforces.com/blog/entry/45310">http://codeforces.com/blog/entry/45310</a>.<br />
Let Adj(i) be the adjacent nodes to i, Ring(s, d) be the nodes which shortest distance from s is d. The strategy to solve this problem is by choosing the starting point s that maximises the probability of guessing correctly. When we choose an s, the target is at d distance away with probability |Ring(s,d)|/n. If we guess at step 1, then P(guessing correctly at step 1 | at Ring(s,d)) = 1/|Ring(s,d)|. What if we don't guess at step 1?<br />
<br />
At step 2, target will move to another neighbouring node. If target was in node u, it will move to a neighbour v with probability 1/|Adj(u)|. We compute Neigh(s, d), which is the set of nodes that are a neighbour of at least 1 node in Ring(s, d). For each v in Neigh(s, d), we can compute P(v | Ring) the probability of target ending up at node v, given that it was at a node in Ring(s, d). This is simply the sum of P(v | u) * P(u) over all u, where P(v | u) = 1/|Adj(u)| means the probability of target moving to v from a node u, and P(u) = 1/|Ring(s,d)| is the probability of target in a node u in Ring(s, d), given that it's in the ring.<br />
<br />
Now that we have the distribution, we iterate through all t and choose the one in which we can maximise the probability of guessing correctly. For each t, the distance from the target to t will be revealed, say dt. When we are given this information, what should we do? Let T(dt) be the set of nodes that is in Neigh(s, d) that is dt away from t. For each u in T(dt), we find the one with highest P(u | Ring). Say that node is v_dt. Then the probability of guessing target correctly, given target is dt away from t, is P(v_dt | Ring) / P(T(dt)), where P(T(dt)) is the probability of t is dt away from target.<br />
<br />
So the strategy is to iterate through all node in Neigh(s, d) and compute all possible dt. Then for each dt, we find the maximum P(v_dt | Ring). Then the maximum probability of guessing correctly if we choose node t at step 2 is sum of P(v_dt | Ring)/P(T(dt)) * P(T(dt)) = sum of P(v_dt | Ring) for all possible dt.<br />
<br />
Amongst all t, we choose the one that gives us the maximum probability, and we compare that with the probability from Step 1 to come up with the final maximum probability of Ring(s, d).<br />
<br />
Implementation:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <cassert></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
vector<span style="color: #333333;"><</span>vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> adj;
<span style="color: #333399; font-weight: bold;">int</span> dist[<span style="color: #0000dd; font-weight: bold;">401</span>][<span style="color: #0000dd; font-weight: bold;">401</span>];
constexpr <span style="color: #333399; font-weight: bold;">int</span> inf <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">12345</span>;
<span style="color: #333399; font-weight: bold;">int</span> n;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">FloydWarshal</span>() {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> k<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;k<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>k) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
dist[i][j] <span style="color: #333333;">=</span> min(dist[i][j], dist[i][k] <span style="color: #333333;">+</span> dist[k][j]);
}
}
}
}
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> ring[<span style="color: #0000dd; font-weight: bold;">401</span>][<span style="color: #0000dd; font-weight: bold;">401</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">PrepareRing</span>() {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
ring[i][dist[i][j]].push_back(j);
}
}
}
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> neighbour_adj[<span style="color: #0000dd; font-weight: bold;">401</span>][<span style="color: #0000dd; font-weight: bold;">401</span>];
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">double</span><span style="color: #333333;">></span> neighbour_prob[<span style="color: #0000dd; font-weight: bold;">401</span>][<span style="color: #0000dd; font-weight: bold;">401</span>];
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">PrepareNeighbour</span>() {
<span style="color: #333399; font-weight: bold;">double</span> temp[<span style="color: #0000dd; font-weight: bold;">410</span>];
<span style="color: #333399; font-weight: bold;">int</span> vis[<span style="color: #0000dd; font-weight: bold;">410</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> d<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;d<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>d){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">:</span> ring[i][d]) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> k <span style="color: #333333;">:</span> adj[j]) {
vis[k] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
temp[k] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">:</span> ring[i][d]) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> k <span style="color: #333333;">:</span> adj[j]) {
temp[k] <span style="color: #333333;">+=</span> <span style="color: #6600ee; font-weight: bold;">1.0</span><span style="color: #333333;">/</span>n <span style="color: #333333;">*</span> <span style="color: #6600ee; font-weight: bold;">1.0</span><span style="color: #333333;">/</span>adj[j].size();
vis[k] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">:</span> ring[i][d]) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> k <span style="color: #333333;">:</span> adj[j]) {
<span style="color: #008800; font-weight: bold;">if</span> (vis[k]) {
neighbour_adj[i][d].push_back(k);
neighbour_prob[i][d].push_back(temp[k]);
vis[k] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
}
}
}
}
}
<span style="color: #333399; font-weight: bold;">double</span> <span style="color: #0066bb; font-weight: bold;">SecondProb</span>(<span style="color: #333399; font-weight: bold;">int</span> s, <span style="color: #333399; font-weight: bold;">int</span> d, <span style="color: #333399; font-weight: bold;">int</span> t) {
<span style="color: #333399; font-weight: bold;">double</span> prob_second <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">double</span> <span style="color: #333399; font-weight: bold;">max_for_t</span>[<span style="color: #0000dd; font-weight: bold;">410</span>];
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> neighbour_adj[s][d].size(); <span style="color: #333333;">++</span>i){
<span style="color: #333399; font-weight: bold;">max_for_t</span>[dist[t][neighbour_adj[s][d][i]]]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> neighbour_adj[s][d].size(); <span style="color: #333333;">++</span>i){
<span style="color: #333399; font-weight: bold;">int</span> j <span style="color: #333333;">=</span> neighbour_adj[s][d][i];
<span style="color: #333399; font-weight: bold;">max_for_t</span>[dist[t][j]] <span style="color: #333333;">=</span> max(<span style="color: #333399; font-weight: bold;">max_for_t</span>[dist[t][j]], neighbour_prob[s][d][i]);
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i <span style="color: #333333;"><</span> neighbour_adj[s][d].size(); <span style="color: #333333;">++</span>i) {
prob_second <span style="color: #333333;">+=</span> <span style="color: #333399; font-weight: bold;">max_for_t</span>[dist[t][neighbour_adj[s][d][i]]];
<span style="color: #333399; font-weight: bold;">max_for_t</span>[dist[t][neighbour_adj[s][d][i]]] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
<span style="color: #008800; font-weight: bold;">return</span> prob_second;
}
<span style="color: #333399; font-weight: bold;">double</span> <span style="color: #0066bb; font-weight: bold;">Solve</span>() {
<span style="color: #333399; font-weight: bold;">double</span> max_prob_s;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> s<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;s<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>s){
<span style="color: #333399; font-weight: bold;">double</span> prob_s <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> d<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;d<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>d){
<span style="color: #333399; font-weight: bold;">double</span> <span style="color: #333399; font-weight: bold;">max_prob_t</span> <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">if</span> (ring[s][d].empty()) <span style="color: #008800; font-weight: bold;">continue</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> t<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;t<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>t){
<span style="color: #333399; font-weight: bold;">double</span> <span style="color: #333399; font-weight: bold;">prob_t</span> <span style="color: #333333;">=</span> max(<span style="color: #6600ee; font-weight: bold;">1.0</span><span style="color: #333333;">/</span>n, SecondProb(s, d, t));
<span style="color: #333399; font-weight: bold;">max_prob_t</span> <span style="color: #333333;">=</span> max(<span style="color: #333399; font-weight: bold;">prob_t</span>, <span style="color: #333399; font-weight: bold;">max_prob_t</span>);
}
prob_s <span style="color: #333333;">+=</span> <span style="color: #333399; font-weight: bold;">max_prob_t</span>;
}
max_prob_s <span style="color: #333333;">=</span> max(prob_s, max_prob_s);
}
<span style="color: #008800; font-weight: bold;">return</span> max_prob_s;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
<span style="color: #333399; font-weight: bold;">int</span> m;
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>m);
<span style="color: #333399; font-weight: bold;">int</span> u,v;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
dist[i][j]<span style="color: #333333;">=</span>inf;
}
dist[i][i]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
}
adj.resize(n);
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>m;<span style="color: #333333;">++</span>i){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>u,<span style="color: #333333;">&</span>v);
u<span style="color: #333333;">--</span>;v<span style="color: #333333;">--</span>;
adj[u].push_back(v);
adj[v].push_back(u);
dist[u][v] <span style="color: #333333;">=</span> dist[v][u] <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
}
FloydWarshal();
PrepareRing();
PrepareNeighbour();
printf(<span style="background-color: #fff0f0;">"%.12f</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,Solve());
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />
The run time complexity analysis is another cool thing about this problem. The argument goes as follows: Fix start node s and current distance d. On step 1, we iterate through Ring(s, d). On step 2, we will at most iterate through Ring(s, d-1), Ring(s, d) and Ring(s, d+1). Then by checking the iteration s, d-1 and s, d+1, we conclude that Ring(s, d) is at most iterated 4 times, and hence overall every node in the graph is iterated at most 4 times, which is O(n) after going through all d, fixing s and t. Hence overall complexity is O(n^3).Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-83055825508602045252016-06-14T13:26:00.002+08:002016-08-07T11:04:28.498+08:00Three prisoners paradoxThis is quite a famous paradox and it's quite mind boggling indeed without careful analysis. It goes like this:<br />
Three prisoners X, M and N are on a death row, however one of them will be pardoned. X asks the guard whether he will be pardoned, however the guard can't tell him that, but instead tells him that M will be executed. Now X believes that his chance of survival increases from 1/3 to 1/2. However, the truth is that X's chance of survival has not changed a bit, and miraculously it is N's chance of being pardoned that has increased from 1/3 to 2/3!<br />
<br />
<a name='more'></a><br /><br />
There are various ways to show this, the one that I am most comfortable with is by using these two theorems:<br />
1. P(A|B) = P(A and B)/P(B) = P(B|A)*P(A)/P(B) (definition of conditional probability and Bayes' Theorem)<br />
2. P(A) = sum of P(A, b) over b (marginalisation)<br />
<br />
The description of the paradox assumes a uniform distribution where each of the outcomes (X dies, M dies, N alive), (X dies, M alive, N dies), and (X alive, M dies, and N dies) is given equal probability, i.e. 1/3. Now the key thing is to differentiate between these two statements:<br />
S1. Probability of X alive, given M dies.<br />
S2. Probability of X alive, given the guard tells X that M dies.<br />
<br />
S1 has a totally different sample space as compared to S2. In S1, we now have either (X dies, M dies, N alive) or (X alive, M dies, N dies), which gives P(X alive given M dies) = 1/2. There is nothing wrong with this. That is why it seems paradoxical. However, the problem above implies S2.<br />
<br />
S2 on the other hand has a sample space (who guard told X will die, fate of X, fate of M, fate of N). And also, the distribution of this sample space is certainly not uniform! Let G denote who the guard names (and to bring up GoT reference, a man needs a name...). We now consider:<br />
1. P(G=M | X dies). The guard can't tell X that he will die, so the guard must name the other person who dies, which in this case M. Hence P(G=M | X dies) = 1.<br />
2. P(G=M | X alive). The guard can choose to name either M or N. Hence P(G=M | X alive) = 1/2.<br />
Now what we really want is P(X alive| G=M). This can be computed by using the above rules I mentioned:<br />
P(X alive| G = M) = P(G=M | X alive) * P(X alive)/P(G=M)<br />
And we have P(G=M) = P(G=M| X alive) * P(X alive) + P(G=M| X dies) * P(X dies), which gives us<br />
P(X alive | G = M) = P(G=M | X alive) * P(X alive) / [P(G=M| X alive) * P(X alive) + P(G=M| X dies) * P(X dies)] (which is basically Bayes' Theorem) = 1/2 * 1/3 / (1/2 * 1/3 + 1 * 1/3) = 1/3.<br />
Hence P(X alive | G = M) = 1/3 which shows that X's chance of survival has not changed, as desired.Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-47135451652645419022016-06-13T08:20:00.000+08:002016-08-07T11:04:48.298+08:00Codeforces Round #356 (Div. 2) E / (Div. 1) C - Bear and Square GridProblem Statement:<br />
<a href="http://codeforces.com/contest/679/problem/C">Codeforces Round #356 (Div. 2) E / (Div. 1) C - Bear and Square Grid</a><br />
<br />
Summary:<br />
A \(N \times N\) grid where a cell is either empty or not, has the following properties: an empty cell is connected to its up, left, right, or bottom neighbour if its neighbour is also an empty cell. Compute the largest possible connected component in the grid, if we can perform one operation of transforming a \(k \times k\) square in the grid into empty cells.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
The solution employs a cool technique. The strategy is to check every possible placement of the \(k \times k\) square and record the maximum connected component obtained. The key is to make this strategy work in time.<br />
<br />
Suppose that we have already computed all the connected components in the initial grid, such that we have the following informations:<br />
- m[i][j] is the key of the connected component in which cell (i, j) belongs to.<br />
- sz[key] is the size of the connected component 'key'.<br />
<br />
The strategy is to perform a sliding window operation on each row of the grid. On each row, we form the \(k \times k\) square from the left side, and slide it one cell at a time to the right end of the row. We keep track of the number of non-empty cells that our current square covers, and also of all the connected components covered in the square.<br />
<br />
When we slide our \(k \times k\) square to the right, say that our square currently covers column [L, L+k-1], what we do is we "peel off" the contributions from the column L of our square, and we add the contributions from column L+k, hence forming a new square [L+1, L+k] in O(k) time.<br />
<br />
Also, for each position of the square, we check the upper, bottom, left and right cells that touches the border of our square for connected components. These connected components are now connected together because of our square and hence can be added to the total size of the connected component formed by our square. This check will also take O(k) per square.<br />
<br />
Hence the total runtime complexity of this strategy is O(k*N*N).<br />
<br />
Implementation:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <deque></span>
<span style="color: #557799;">#include <string></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> n, k;
<span style="color: #333399; font-weight: bold;">int</span> a[<span style="color: #0000dd; font-weight: bold;">510</span>][<span style="color: #0000dd; font-weight: bold;">510</span>];
<span style="color: #333399; font-weight: bold;">int</span> m[<span style="color: #0000dd; font-weight: bold;">510</span>][<span style="color: #0000dd; font-weight: bold;">510</span>]; <span style="color: #888888;">// map entry i j to key k</span>
<span style="color: #333399; font-weight: bold;">int</span> vis[<span style="color: #0000dd; font-weight: bold;">510</span>][<span style="color: #0000dd; font-weight: bold;">510</span>];
<span style="color: #333399; font-weight: bold;">int</span> sz[<span style="color: #0000dd; font-weight: bold;">510</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">510</span>], vis_key[<span style="color: #0000dd; font-weight: bold;">510</span><span style="color: #333333;">*</span><span style="color: #0000dd; font-weight: bold;">510</span>];
<span style="color: #333399; font-weight: bold;">int</span> ans, cnt;
vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> backstack;
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ClearBackstack</span>() {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>backstack.size();<span style="color: #333333;">++</span>i){
vis_key[backstack[i]]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
}
backstack.clear();
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">ComputeSlice</span>(<span style="color: #333399; font-weight: bold;">int</span> row, <span style="color: #333399; font-weight: bold;">int</span> j, vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>*</span> bstack,
<span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">*</span> extra) {
<span style="color: #333399; font-weight: bold;">int</span> sum <span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>row;i<span style="color: #333333;"><</span>row<span style="color: #333333;">+</span>k;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>a[i][j]) {
sum <span style="color: #333333;">+=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>vis_key[m[i][j]]) {
<span style="color: #333333;">*</span>extra <span style="color: #333333;">+=</span> sz[m[i][j]];
}
vis_key[m[i][j]]<span style="color: #333333;">++</span>;
bstack<span style="color: #333333;">-></span>push_back(m[i][j]);
}
}
<span style="color: #008800; font-weight: bold;">return</span> sum;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">ClearSlice</span>(<span style="color: #008800; font-weight: bold;">const</span> vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>&</span> bstack, <span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">*</span> extra) {
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>; i<span style="color: #333333;"><</span>bstack.size(); <span style="color: #333333;">++</span>i) {
vis_key[bstack[i]]<span style="color: #333333;">--</span>;
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>vis_key[bstack[i]]) {
<span style="color: #333333;">*</span>extra <span style="color: #333333;">-=</span> sz[bstack[i]];
}
}
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">CheckRow</span>(<span style="color: #333399; font-weight: bold;">int</span> row, <span style="color: #333399; font-weight: bold;">int</span> col) {
<span style="color: #888888;">// [col ... col+k-1]</span>
<span style="color: #008800; font-weight: bold;">if</span> (row <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> row <span style="color: #333333;">>=</span> n) <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> sum<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span>col;j<span style="color: #333333;"><</span>col<span style="color: #333333;">+</span>k;<span style="color: #333333;">++</span>j){
<span style="color: #008800; font-weight: bold;">if</span>(a[row][j] <span style="color: #333333;">&&</span> <span style="color: #333333;">!</span>vis_key[m[row][j]]) {
vis_key[m[row][j]]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
backstack.push_back(m[row][j]);
sum <span style="color: #333333;">+=</span> sz[m[row][j]];
}
}
<span style="color: #008800; font-weight: bold;">return</span> sum;
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">CheckCol</span>(<span style="color: #333399; font-weight: bold;">int</span> col, <span style="color: #333399; font-weight: bold;">int</span> row) {
<span style="color: #888888;">// [row ... row+k-1]</span>
<span style="color: #008800; font-weight: bold;">if</span> (col <span style="color: #333333;"><</span> <span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> col <span style="color: #333333;">>=</span> n) <span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> sum<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span>row;i<span style="color: #333333;"><</span>row<span style="color: #333333;">+</span>k;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">if</span>(a[i][col] <span style="color: #333333;">&&</span> <span style="color: #333333;">!</span>vis_key[m[i][col]]) {
vis_key[m[i][col]]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
backstack.push_back(m[i][col]);
sum <span style="color: #333333;">+=</span> sz[m[i][col]];
}
}
<span style="color: #008800; font-weight: bold;">return</span> sum;
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">dfs</span>(<span style="color: #333399; font-weight: bold;">int</span> i, <span style="color: #333399; font-weight: bold;">int</span> j) {
<span style="color: #008800; font-weight: bold;">if</span> (i<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> j<span style="color: #333333;"><</span><span style="color: #0000dd; font-weight: bold;">0</span> <span style="color: #333333;">||</span> i<span style="color: #333333;">>=</span>n <span style="color: #333333;">||</span> j<span style="color: #333333;">>=</span>n) <span style="color: #008800; font-weight: bold;">return</span>;
<span style="color: #008800; font-weight: bold;">if</span> (vis[i][j]) <span style="color: #008800; font-weight: bold;">return</span>;
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>a[i][j]) <span style="color: #008800; font-weight: bold;">return</span>;
vis[i][j]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
m[i][j]<span style="color: #333333;">=</span>cnt;
sz[cnt]<span style="color: #333333;">++</span>;
dfs(i<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>,j);
dfs(i<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>,j);
dfs(i,j<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
dfs(i,j<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>);
}
<span style="color: #333399; font-weight: bold;">void</span> <span style="color: #0066bb; font-weight: bold;">Solve</span>() {
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i)<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j)m[i][j]<span style="color: #333333;">=-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
ans <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
cnt <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
<span style="color: #008800; font-weight: bold;">if</span> (<span style="color: #333333;">!</span>a[i][j] <span style="color: #333333;">||</span> vis[i][j]) <span style="color: #008800; font-weight: bold;">continue</span>;
sz[cnt]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
dfs(i, j);
cnt<span style="color: #333333;">++</span>;
}
}
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> row<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;row<span style="color: #333333;">+</span>k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>row){
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>cnt;<span style="color: #333333;">++</span>i) vis_key[i]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
deque<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">></span> window;
deque<span style="color: #333333;"><</span>vector<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int</span><span style="color: #333333;">>></span> bstack;
<span style="color: #333399; font-weight: bold;">int</span> sum <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #333399; font-weight: bold;">int</span> extra <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #888888;">// prepare first window</span>
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>k;<span style="color: #333333;">++</span>j){
bstack.push_back({});
window.push_back(ComputeSlice(row, j, <span style="color: #333333;">&</span>bstack.back(), <span style="color: #333333;">&</span>extra));
sum <span style="color: #333333;">+=</span> window.back();
}
<span style="color: #333399; font-weight: bold;">int</span> cur <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #888888;">// compute, then slide</span>
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;">+</span>k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span><span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
cur <span style="color: #333333;">=</span> sum<span style="color: #333333;">+</span>extra;
cur <span style="color: #333333;">+=</span> CheckRow(row<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, j);
cur <span style="color: #333333;">+=</span> CheckRow(row<span style="color: #333333;">+</span>k, j);
cur <span style="color: #333333;">+=</span> CheckCol(j<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>, row);
cur <span style="color: #333333;">+=</span> CheckCol(j<span style="color: #333333;">+</span>k, row);
ans <span style="color: #333333;">=</span> max(ans, cur);
ClearBackstack();
<span style="color: #008800; font-weight: bold;">if</span> (j<span style="color: #333333;">!=</span>n<span style="color: #333333;">-</span>k) {
sum <span style="color: #333333;">-=</span> window.front();
window.pop_front();
ClearSlice(bstack.front(), <span style="color: #333333;">&</span>extra);
bstack.pop_front();
bstack.push_back({});
window.push_back(ComputeSlice(row, j<span style="color: #333333;">+</span>k, <span style="color: #333333;">&</span>bstack.back(), <span style="color: #333333;">&</span>extra));
sum <span style="color: #333333;">+=</span> window.back();
}
}
}
printf(<span style="background-color: #fff0f0;">"%d</span><span style="background-color: #fff0f0; color: #666666; font-weight: bold;">\n</span><span style="background-color: #fff0f0;">"</span>,ans);
}
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">main</span>(){
scanf(<span style="background-color: #fff0f0;">"%d%d"</span>,<span style="color: #333333;">&</span>n,<span style="color: #333333;">&</span>k);
string s;
<span style="color: #008800; font-weight: bold;">for</span>(<span style="color: #333399; font-weight: bold;">int</span> i<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;i<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>i){
cin <span style="color: #333333;">>></span> s;
<span style="color: #008800; font-weight: bold;">for</span> (<span style="color: #333399; font-weight: bold;">int</span> j<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;j<span style="color: #333333;"><</span>n;<span style="color: #333333;">++</span>j){
<span style="color: #008800; font-weight: bold;">if</span>(s[j]<span style="color: #333333;">==</span><span style="color: #0044dd;">'X'</span>) a[i][j]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">0</span>;
<span style="color: #008800; font-weight: bold;">else</span> a[i][j]<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
Solve();
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-301908746119538702016-06-12T07:37:00.000+08:002016-08-07T11:05:12.823+08:00Codeforces Round #356 (Div. 2) D. Bear and Tower of CubesProblem Statement:<br />
<a href="http://codeforces.com/contest/680/problem/D">Codeforces Round #356 (Div. 2) D. Bear and Tower of Cubes</a><br />
<br />
Summary:<br />
Given m < 10^15, find the largest (k, X) such that a[1]+a[2]+...+a[k] = X <= m, each a[i] is a perfect cube, and for a given X, a[i] is the largest cube such that a[1] + ... + a[i] <= X.<br />
<br />
<a name='more'></a><br /><br />
Solution:<br />
The editorial has a very nice solution: <a href="http://codeforces.com/blog/entry/45310">http://codeforces.com/blog/entry/45310</a>. I am discussing the solution here mostly for my own future reference.<br />
The idea in the solution is a complete search on choices of cubes. Let Max(m) be the recursion that returns k the maximum length of cube tower that can be constructed and X the maximum sum we can get from such tower such that X <= m.<br />
Let a be an integer such that a^3 <= m < (a+1)^3. The first cube can be of length 1 to a. If the length of the first cube is chosen to be a, then we recursively compute Max(m-a^3).<br />
Otherwise, if the first cube is chosen to be a-1, then current X must be at most a^3-1, which means the next recursion call is Max((a-1)^3-1-(a-1)^3). We do not consider any other cases below s < a-1, since Max(S) <= Max(T) where S < T, and choosing s < a-1 will lead us to call Max with smaller argument then if we choose a-1.<br />
Hence Max(m) = max{Max(m-a^3) + (1, a^3), Max(a^3-1-(a-1)^3) + (1, (a-1)^3)}.<br />
<br />
Another cool thing about this solution is that we can make bounds on the runtime complexity:<br />
Since each call Max(m) will lead to call to Max(m-a^3) and Max(a^3-1-(a-1)^3), where m is a polynomial of degree 3 in terms of a. Notice that both m-a^3 and a^3-1-(a-1)^3 has degree at most 2 in terms of a, hence there is a reduction from m = O(a^3) to O(a^2) which means each call on Max reduces its argument by power of 2/3. From here we can empirically compute k that reduces m = 10^15 to 1, and we get k somewhere around k = 18 to 19 steps, and hence by expanding the recursion tree we know that Max() is called at most 2^(k+1)-1 times or at most 2^20-1.<br />
<br />
Code:<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;"><span style="color: #557799;">#include <iostream></span>
<span style="color: #557799;">#include <cstdio></span>
<span style="color: #557799;">#include <algorithm></span>
<span style="color: #557799;">#include <vector></span>
<span style="color: #557799;">#include <utility></span>
<span style="color: #557799;">#include <map></span>
<span style="color: #008800; font-weight: bold;">using</span> <span style="color: #008800; font-weight: bold;">namespace</span> std;
<span style="color: #333399; font-weight: bold;">int</span> <span style="color: #0066bb; font-weight: bold;">GetK</span>(<span style="color: #333399; font-weight: bold;">int64_t</span> m) {
<span style="color: #333399; font-weight: bold;">int</span> lo<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">1</span>,hi<span style="color: #333333;">=</span><span style="color: #0000dd; font-weight: bold;">100000</span>, mid;
<span style="color: #008800; font-weight: bold;">while</span>(lo<span style="color: #333333;"><=</span>hi) {
mid <span style="color: #333333;">=</span> (lo<span style="color: #333333;">+</span>hi)<span style="color: #333333;">/</span><span style="color: #0000dd; font-weight: bold;">2</span>;
<span style="color: #333399; font-weight: bold;">int64_t</span> cur <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>mid<span style="color: #333333;">*</span>mid<span style="color: #333333;">*</span>mid;
<span style="color: #008800; font-weight: bold;">if</span> (cur <span style="color: #333333;"><</span> m) {
lo <span style="color: #333333;">=</span> mid<span style="color: #333333;">+</span><span style="color: #0000dd; font-weight: bold;">1</span>;
} <span style="color: #008800; font-weight: bold;">else</span> {
hi <span style="color: #333333;">=</span> mid<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>;
}
}
<span style="color: #333399; font-weight: bold;">int64_t</span> cur <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>lo<span style="color: #333333;">*</span>lo<span style="color: #333333;">*</span>lo;
<span style="color: #008800; font-weight: bold;">if</span> (cur <span style="color: #333333;">==</span> m) <span style="color: #008800; font-weight: bold;">return</span> lo;
<span style="color: #008800; font-weight: bold;">return</span> hi;
}
pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span>, <span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> MaxCubes(<span style="color: #333399; font-weight: bold;">int64_t</span> m) {
<span style="color: #008800; font-weight: bold;">if</span> (m <span style="color: #333333;"><=</span> <span style="color: #0000dd; font-weight: bold;">0</span>) <span style="color: #008800; font-weight: bold;">return</span> {<span style="color: #0000dd; font-weight: bold;">0</span>, <span style="color: #0000dd; font-weight: bold;">0</span>};
<span style="color: #333399; font-weight: bold;">int</span> k <span style="color: #333333;">=</span> GetK(m);
<span style="color: #333399; font-weight: bold;">int64_t</span> k3 <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>k<span style="color: #333333;">*</span>k<span style="color: #333333;">*</span>k;
<span style="color: #333399; font-weight: bold;">int64_t</span> k_13 <span style="color: #333333;">=</span> <span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">*</span>(k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>)<span style="color: #333333;">*</span>(k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>)<span style="color: #333333;">*</span>(k<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1</span>);
pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span>, <span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> s <span style="color: #333333;">=</span> MaxCubes(m<span style="color: #333333;">-</span>k3);
pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span>, <span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> t <span style="color: #333333;">=</span> MaxCubes(k3<span style="color: #333333;">-</span><span style="color: #0000dd; font-weight: bold;">1LL</span><span style="color: #333333;">-</span>k_13);
s.first <span style="color: #333333;">+=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
s.second <span style="color: #333333;">+=</span> k3;
t.first <span style="color: #333333;">+=</span> <span style="color: #0000dd; font-weight: bold;">1</span>;
t.second <span style="color: #333333;">+=</span> k_13;
<span style="color: #008800; font-weight: bold;">if</span> (s.first <span style="color: #333333;">==</span> t.first) {
<span style="color: #008800; font-weight: bold;">return</span> s.second <span style="color: #333333;">></span> t.second <span style="color: #333333;">?</span> s <span style="color: #333333;">:</span> t;
}
<span style="color: #008800; font-weight: bold;">return</span> s.first <span style="color: #333333;">></span> t.first <span style="color: #333333;">?</span> s <span style="color: #333333;">:</span> t;
}
<span style="color: #333399; font-weight: bold;">int</span> main(){
<span style="color: #333399; font-weight: bold;">int64_t</span> m;
cin <span style="color: #333333;">>></span> m;
pair<span style="color: #333333;"><</span><span style="color: #333399; font-weight: bold;">int64_t</span>,<span style="color: #333399; font-weight: bold;">int64_t</span><span style="color: #333333;">></span> p <span style="color: #333333;">=</span> MaxCubes(m);
cout <span style="color: #333333;"><<</span> p.first <span style="color: #333333;"><<</span> <span style="background-color: #fff0f0;">" "</span> <span style="color: #333333;"><<</span> p.second <span style="color: #333333;"><<</span> endl;
<span style="color: #008800; font-weight: bold;">return</span> <span style="color: #0000dd; font-weight: bold;">0</span>;
}
</pre>
</div>
<br />Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com0tag:blogger.com,1999:blog-4816432343216370550.post-13601962678066037052016-06-06T10:32:00.002+08:002016-08-07T11:05:36.053+08:00Data Structure: Fenwick Tree and Range UpdateSomething led me to read up on Fenwick Tree (a.k.a Binary Indexed Tree). There are lots of great tutorials that explain what this data structure is, and how it is useful. A google search is all you need. I would like to write up some short discussion on the tree, and also about a technique that is used to allow this tree to support range updates.<br />
<div>
<br />
<a name='more'></a><br /></div>
<div>
<u>1. What's the motivation behind this data structure?</u></div>
<div>
Being the friend of Segment Tree, Fenwick Tree is designed to answer ranged queries efficiently. Historically it is used mostly for calculating cumulative frequencies, or in other words, the sum of values in range [i, j]. It actually can only handle queries in the form [1, j], but in the case of cumulative frequency, one can first query [1, j], and then query [1, i-1], and subtract the result for a desired effect.</div>
<div>
<br /></div>
<div>
<u>2. What's it look like?</u></div>
<div>
Using the array A = [1, 4, -3, 5, 6, 1, 3, -1, 0, 2], a Fenwick tree looks like this:<br />
<br />
<!-- HTML generated using hilite.me --><br />
<div style="background: #ffffff; border-width: 0.1em 0.1em 0.1em 0.8em; border: solid gray; overflow: auto; padding: 0.2em 0.6em; width: auto;">
<pre style="line-height: 125%; margin: 0;">i 1 2 3 4 5 6 7 8 9 10
A 1, 4, -3, 5, 6, 1, 3, -1, 0, 2
fenwick 1, 5, -3, 7, 6, 7, 3, 16, 0, 2
2D representation:
16
+---------+----+----+
7 | |
+----+----+ | |
5 | 7 | 2
+----+ | +----+ | +----+
1 4 -3 5 6 1 3 -1 0 2
0001 0010 0011 0100 0101 0110 0111 1000 1001 1010
</pre>
</div>
</div>
<div>
<br /></div>
<div>
<u>3. Where is the tree?</u></div>
<div>
It was weird that it is kind of difficult for me to think about Fenwick Tree as a tree, despite its name. After some contemplation, I think the parent-child relationship of a Fenwick Tree can be described as follows:<br />
1) A node with value v with binary representation A1B where B is made up of zero bits (i.e. the 1 in A1B denotes the rightmost bit 1 in v) is the parent of A01000[...]0, A01100[...]0, A01110[...]0, and so on until A01111[...]1. Hence the parent of node v can be computed as v + (v & -v). So more concretely, v is a child of v + (v & -v).<br />
2) If v = A1B (where B is zero bits), then that node covers the sum from A0B+1 to A1B. This is the motivating construction of fenwick tree, it allows us to compute a range query in O(log n) time (where log n is the length of the bits representation of v). To see this, suppose that v = A1B1C where B and C are zero bits (hence the 1s in v represents the two rightmost 1 bits of v). Then we know that A1B1C covers the value from [A1B0C+1] to A1B1C. All we need to find is now the total sum from 1 to A1B0C(where B0C is all 0 bits, which is hence a recursive operation! ). By 'peeling' off the rightmost 1 bit one by one, we can compute the total sum from 1 to v. This peeling operation is represented as v - (v & -v) (we can also see this as jumping to the left sibling of node v).<br />
<br />
<u>4. Code for Range query and Update:</u><br />
Range query [1,v] is hence supported as follows:<br />
<span style="font-family: "courier new" , "courier" , monospace;">rmq(v):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">while (v) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> rmq += fenwick[v]; // or rmq = min(fenwick[v], rmq) for RMQ</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> v -= v & -v;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
On the other hand, update with incremental value val is represented as follow:<br />
<span style="font-family: "courier new" , "courier" , monospace;">update(v, val):</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">while (v <= length) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> fenwick[tree] += val; // or fenwick[v] = min(fenwick[v], val).</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> v += v & v;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
Notice that we only support 'incremental changes', like adding/subtracting some delta, or by performing monotonic minimisation/maximisation.<br />
<br />
<u>5. Range update?</u><br />
Notice also that the update procedure above only handle one entry at a time. As it turns out, there is a way to provide a range update for cumulative frequency by manipulation 2 Fenwick trees at a time.<br />
Firstly, suppose that we have two arrays mult and offset. When we perform a range update on [3, 5] with value +2 for example, we set the values in mult as follows:<br />
<span style="font-family: "courier new" , "courier" , monospace;">mult : [ 0 0 2 2 2 0 0]</span><br />
While offset is set as follows:<br />
<span style="font-family: "courier new" , "courier" , monospace;">offset: [ 0 0 4 4 4 -6 -6]</span><br />
<span style="font-family: inherit;">Of course if we have performed that range update on our cumulative array, it will look like this:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">sum : [ 0 0 2 4 6 6 6]</span><br />
How does that help? When we want to compute the value of the cumulative frequence at index i after the update, we calculate sum[i] = i * mult[i] - offset. Hence for example:<br />
at i = 3, sum[3] = 3 * 2 - 4 = 2.<br />
at i = 5, sum[5] = 5 * 2 - 4 = 6.<br />
at i = 6, sum[6] = 6 * 0 - (-6) = 6.<br />
Hence we can recover the value of sum[i] from both mult[i] and offset[i]. Now, if both mult and offset are fenwick trees, we can perform the updates as follows: mult.update(3, 2) and then mult.update(6, -2). And we can perform the following to offset: offset.update(3, 4) and offset.update(6, -10). Then sum[i] can be computed as mult.rmq(i) * i - offset.rmq(i).<br />
<br />
More generally, we have:<br />
<span style="font-family: "courier new" , "courier" , monospace;">update(left, right, val) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> mult.update(left, val);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> mult.update(right+1, -val);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> offset.update(left, (left-1)*val);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> offset.update(right+1, -right*val);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">rmq(i) {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> return mult.rmq(i) * i - offset.rmq(i)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">}</span><br />
<br />
<u>6. Additional note: Fun technique</u><br />
So the above trick of splitting updates into multiplication and offsetting is quite interesting, people who come up with those by themselves are indeed geniuses. But the more interesting trick for me is actually the part where we reduce the range update on the underlying mult and offset to sublinear complexity.<br />
<br />
The observation is: to perform an update such as: increment/decrement by val from index i to N on an array, we can instead perform an update on a fenwick tree at index i with that value. This technique essentially pushed down the running time complexity of the above range update from O(N) to O(lg N).<br />
<br />
To see this more clearly we can think about an array, for example A = [1, 2, 3, 2]. Suppose that we convert A into a fenwick tree representation FA such that FA.rmq(i) = A[i] (This can be done by iterating through elements in A and perform an update on FA at position i with value A[i]-A[i-1]). Now if we want to make a range update from [L, R] by +val, first we perform an update on FA at position L by value val, then we perform update on FA at R+1 by value -val. The effect of the first operation is that FA.rmq(i) for all i >= L will increase by +val, and the effect of the second operation is such that for all i > R, we make sure that the effect of +val is negated. This achieves the same effect as updating all element in A[L..R] one by one, but with the advantage of using only O(lg N) time.<br />
<br />
Here we make a trade off: indexing is now O(lg N) on FA, as opposed to O(1) at A, but performing a range update on FA is now O(lg N) instead of O(N) as of on A.<br />
<br />
Yeah that's pretty cool.</div>
Prajogo Tiohttp://www.blogger.com/profile/01988589587901587904noreply@blogger.com1