Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The question is essentially asking us to count permutations of <code>1 2 ... N</code> such that <code>i</code> and <code>i+1</code> are not adjacent for <code>1 &lt;= i &lt;= N-1</code>. </p> <p>Additionally, we have a prefix constraint. We should count only those permutations which start with <code>pos_1 pos_2 ... pos_k</code>. </p> <p>If it were not for the prefix constraint, you can find the answer in O(N) time using the formula from <a href="http://oeis.org/A002464" rel="noreferrer">OEIS</a>. That is if <code>N</code> is not too large. The number of digits in the answer grows as Θ(N log N), so multiplication and addition would incur additional overhead. Or you could compute the answer modulo some number. This question was asked in the <a href="http://www.spoj.pl/problems/FLWRS/" rel="noreferrer">Egyptian Olympiad in Informatics (2009)</a>. </p> <p>With the prefix constraint, I have an O(N<sup>2</sup>) dynamic programming solution. However, since N is as small as 16, using a polynomial time algorithm is overkill. There exists an easier dynamic programming solution running in time O(2<sup>N</sup>N<sup>2</sup>). Although this algorithm would probably take longer to code than the previous solution, its much faster to think of. The backtracking solution would, however, take somewhere between 20 to 100 hours (on an ordinary desktop/laptop) to run in the worst case. There are <code>2806878055610</code> solutions alone to visit for N = <code>16</code>. In addition to that, there would probably be a heavy cost of visiting non-solution dead-ends.</p> <h2>O(2<sup>N</sup>N<sup>2</sup>) Solution</h2> <p>This solution can be generalized to finding the number of Hamiltonian paths in a graph.</p> <p>Our state would be a pair <code>(S, i)</code>; where <code>S</code> is a subset of <code>{1,2...N}</code> and <code>i</code> is an element of <code>S</code>. Let the cardinality of <code>S</code> be <code>M</code>. </p> <p>Define <code>F(S,i)</code> to be the number of ways to place the the elements <code>1, 2, ..., M</code> in the positions specified in <code>S</code>; respecting the constraint that <code>k</code> and <code>k+1</code> never appear together; and the element <code>M</code> being placed in position <code>i</code>.</p> <p>The base case is <code>F(P,pos_k) = 1</code> where <code>P = {pos_1, pos_2 ... pos_k}.</code> It is straightforward to compute <code>F(S,i)</code> for all <code>S</code> and <code>i</code> in time O(2<sup>N</sup>N<sup>2</sup>). </p> <p>The final answer is <code>F([N],1) + F([N],2) + ... + F([N],N)</code> where <code>[N] = {1,2...N}</code>.</p> <p>C++ code follows. <a href="http://en.wikipedia.org/wiki/Mask_%28computing%29" rel="noreferrer">Bitmasks</a> were used to represent subsets of <code>{1,2...N}</code>.</p> <pre><code>const int MAXN = 18; long long DP[1 &lt;&lt; MAXN][MAXN]; void solve() { int n, k; cin &gt;&gt; n &gt;&gt; k; int pmask = 0, p; for(int i = 0; i &lt; k; i++){ cin &gt;&gt; p; pmask |= (1&lt;&lt;p); } // base cases if(k &gt; 0) { DP[pmask][p] = 1; } else { for(int i = 0; i &lt; n; i++) DP[1&lt;&lt;i][i] = 1; } long long ans = 0; for(int bitmask = pmask; bitmask &lt; (1&lt;&lt;n); bitmask++) { for(int i = 0; i &lt; n; i++){ for(int j = 0; j &lt; n; j++){ if((bitmask &amp; (1&lt;&lt;j)) or abs(i-j) == 1) continue; DP[bitmask | (1&lt;&lt;j)][j] += DP[bitmask][i]; } if(bitmask == ((1&lt;&lt;n) - 1)) ans += DP[bitmask][i]; } } cout &lt;&lt; ans &lt;&lt; endl; } </code></pre> <h2>O(N<sup>2</sup>) Solution</h2> <p>This solution is pretty difficult to think of if you have not come across the idea before. </p> <p>First, let's tackle the problem without the prefixes. </p> <p>The idea is to 'build' all valid permutations by placing the elements 1, 2 .. N one by one.</p> <p>Let's start with an illustration. Suppose we are building a permutation, of say, 1 2 .. 5. First, we place 1. After placing 1, we also insert a placeholder element to be filled in by later numbers. More precisely, each state is a class of permutations where the placeholder <code>x</code> is replaced by a non-empty sequence of elements. </p> <p>Our permutation, after inserting 1, looks like one of the 3 cases:</p> <ul> <li><code>1 x</code> - 1 is the first element. The placeholder <code>x</code> would contain all the elements 2,3,4,5 in some order.</li> <li><code>x 1</code> - 1 is the last element. </li> <li><code>x 1 x</code> - 1 is neither the first element or last element.</li> </ul> <p>Next, we place 2. It has to belong to one of the placeholders in one of the previous 3 classes. </p> <ul> <li><p>Suppose it belongs to the only placeholder in <code>1 x</code>. Since 2 cannot be adjacent to 1, after placing 2 we <em>must</em> insert another placeholder between them. This results in the state <code>1 x 2</code>. Additionally, we need to account for the permutations when 2 isn't the last element. We also spawn a state <code>1 x 2 x</code>.</p></li> <li><p>For <code>x 1</code>, we analogously create states <code>2 x 1</code> and <code>x 2 x 1</code>.</p></li> <li><p>For <code>x 1 x</code>, we have two choices of placeholders to place 2 in. Like the previous cases, we create states <code>2 x 1 x</code>, <code>x 2 x 1 x</code>, <code>x 1 x 2</code>, <code>x 1 x 2 x</code>. But notice, for example, in <code>x 2 x 1 x</code> the last placeholder is different from the other two - in that 3 can occur in it without a need to create another barrier! We record this by using a different symbol for the placeholder. That is we use <code>x 2 x 1 o</code> and <code>o 1 x 2 x</code> states instead.</p></li> </ul> <p>Suppose next, we are inserting 3 in <code>x 2 x 1 o</code>. If we place 3 in an <code>x</code>, like before, we have to create a barrier placeholder. But, we do have a choice between creating or omitting a placeholder <em>in the direction opposite</em> to the barrier placeholder. If we place 3 in an <code>o</code> placeholder, we have choices between creating or omitting placeholders <em>in both directions</em>. </p> <p>Additionally, we must also 'promote' the <code>x</code> placeholders that are not used to <code>o</code> placeholders. This is because, the old <code>x</code> placeholders do not offer a constraint for the next element, 4, like they did for 3. </p> <p>We can already start guessing the developing pattern. In the general case, while inserting i:</p> <ul> <li><p>First of all, we have to choose in which placeholder to place i. </p></li> <li><p>Next, suppose we place i in an <code>x</code> placeholder. We must build a barrier placeholder. And we have a choice whether to build a placeholder in the other direction.</p></li> <li><p>If we are using an <code>o</code> placeholder, we have choices to build additional placeholders in both directions. That is, a total of 4 choices.</p></li> <li><p>We must update the <code>x</code> placeholders we did not use, to <code>o</code> placeholders.</p></li> </ul> <p>The final observation that turns this idea into an efficient algorithm is that <strong>we can bunch together permutation classes that have the same number of placed elements and the same number of <code>x</code> and <code>o</code> placeholders</strong>. This is because, for two different classes sharing all three of these parameters, the number of permutations they represent are equal. </p> <p>To prove this claim rigorously, it is enough to observe that the classes we are enumerating are exhaustive and non-overlapping. </p> <h3>Prefixes</h3> <p>A little thought reveals that in the prefix problem, we just have to count permutations which begin with a certain element, (call this b); and some of the constraints between <code>i</code> and <code>i+1</code> are not applicable anymore. </p> <p>The second modification is easy to fix: If the constraint between i-1 and i are not applicable, then before inserting i, update all the <code>x</code> placeholders to <code>o</code> placeholders.</p> <p>For the first modification, we should ensure that there is always a placeholder at the beginning until <code>b</code> is placed. While placing <code>b</code> we cheerfully place it into the beginning placeholder, and don't add any placeholder before it.</p> <h3>Implementation</h3> <p>Let <code>DP[i][no][nx]</code> be the number of ways to build the class where the first <code>i</code> elements have been placed, and there are <code>no</code> and <code>nx</code> placeholders of type <code>o</code> and <code>x</code> respectively. At any state, the number of <code>x</code> placeholders is between 0 and 2. So the state space is O(N^2). State transitions are constant time, exactly as described above.</p> <h2>O(N) solution for the problem without the prefix constraint</h2> <p>According to OEIS, <em>A<sub>n</sub> = (n+1)A<sub>n-1</sub> - (n-2)A<sub>n-2</sub> - (n-5)A<sub>n-3</sub> + (n-3)A<sub>n-4</sub></em>; where <em>A<sub>n</sub></em> is the number of permutations where <code>i</code> and <code>i+1</code> are never consecutive.</p> <p>We can compute the sequence A<sub>n</sub> in O(n). (That is, assuming we compute A<sub>n</sub> modulo a reasonably small number.)</p> <p>Here is a derivation of the formula:</p> <p>Define auxiliary sequences: </p> <ul> <li><p>B<sub>n</sub> = Number of permutations of <code>1 2 ... N</code> such that <strong>exactly one</strong> of the <code>N-1</code> adjacency constraint is violated.</p></li> <li><p>C<sub>n</sub> = Number of permutations of <code>1 2 ... N</code> such that <strong>only</strong> the adjacency constraint involving the element <code>N</code> is violated. That is <code>N-1</code> and <code>N</code> would be adjacent to each other in these permutation; and all other adjacency constraints are satisfied.</p></li> </ul> <p>We now look for recurrences for the sequences A, B and C.</p> <p><strong>Recurrence for A<sub>n</sub></strong></p> <p>Suppose we remove the element <code>n</code> from a valid permutation <code>P</code>, where <code>i</code> and <code>i+1</code> are never adjacent. The resulting permutation <code>Q</code> of <code>1 .. n-1</code> must satisfy exactly one of the following two cases:</p> <ul> <li><p>No adjacent numbers from <code>1 ... n-1</code> are adjacent in <code>Q</code>. That is, <code>Q</code> is one of the permutations accounted for in A<sub>n-1</sub>. </p></li> <li><p>Exactly one pair <code>(i,i+1)</code> appear consecutively in <code>Q</code>, and <code>i+1 =/= n-1</code>. That is, <code>Q</code> is a permutation from B<sub>n-1</sub> - C<sub>n-1</sub>.</p></li> </ul> <p>In the first case, element <code>n</code> can be inserted in exactly <code>n - 2</code> positions. Two of the positions are blocked by the element <code>n - 1</code>. In the second case, there is only one choice for the position of <code>n</code> - between the consecutive elements.</p> <p>We get the recurrence: <strong><em>A<sub>n</sub> = (n - 2)A<sub>n-1</sub> + B<sub>n-1</sub> - C<sub>n-1</sub></em></strong>.</p> <p><strong>Recurrence for B<sub>n</sub></strong></p> <p>Let B<sub>n,k</sub> be the number of permutations where <code>k</code> and <code>k+1</code> occur consecutively. We can coalesce <code>k</code> and <code>k+1</code> together to a single element, and consider a permutation <code>Q</code> of <code>n-1</code> elements, preserving the relative ordering. </p> <ul> <li><p>If neither <code>k-1</code> and <code>k+2</code> (original labels) appear next to the coalesced <code>(k,k+1)</code> element, then <code>Q</code> contributes <code>2</code> permutations to <em>B<sub>n,k</sub></em> - they correspond to the arrangements <code>k k+1</code> and <code>k+1 k</code> within the coalesced element. The number of such <code>Q</code> is <em>A<sub>n-1</sub></em>.</p></li> <li><p>If one of <code>k-1</code> or <code>k+2</code> appear next to the <code>(k,k+1)</code> element, then <code>Q</code> contributes <code>1</code> permutation. The number of such <code>Q</code> is <em>B<sub>n-1,k-1</sub> + B<sub>n-1,k</sub></em>.</p></li> <li><p>If both <code>k-1</code> and <code>k+2</code> appear next to the <code>(k,k+1)</code> element, then <code>Q</code> contributes <code>1</code> permutation. The number of such <code>Q</code> is <em>B<sub>n-2,k-1</sub></em>.</p></li> </ul> <p>We have <em>B<sub>n,k</sub> = 2A<sub>n-1</sub> + B<sub>n-1,k-1</sub> + B<sub>n-1,k</sub> + B<sub>n-2,k-1</sub></em>. (Some terms vanish when <code>k = 1 and k = n-1</code>). </p> <p>Summing over <code>k</code>, we get the recurrence: <strong><em>B<sub>n</sub> = 2(n-1)A<sub>n-1</sub> + 2B<sub>n-1</sub> + B<sub>n-2</sub></em></strong>.</p> <p><strong>Recurrence for C<sub>n</sub></strong></p> <p>Well, <em>C<sub>n</sub></em> is just <em>B<sub>n,n-1</sub></em>. From the previous results, it follows that <strong><em>C<sub>n</sub> = 2A<sub>n-1</sub> + C<sub>n-1</sub></em></strong>.</p> <p><strong>Putting it all together</strong></p> <p>We should be able to eliminate <em>B</em> and <em>C</em> to get a recurrence in <em>A</em> alone. It is left as an exercise. :-)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload