Misuki's blog

By Misuki, 5 months ago, In English

Hello codeforces community! Today I want to share my solution to a counting problem from recent contest: 1842G — Tenzing and Random Operations.

But first, why would I write a blog specifically for this problem? Because I found out this solution comprises a lot of common technique in counting problems and basic problem solving skill, which may be served as a wrap up of standard counting technique and idea used in CP, also providing an evidence that you can solve recent CF problems by just mastering the basic problem solving skill and common techniques, even on a 2800* one! And last but not least, provide an alternative solution to the problem :)

Now, let get started with the solution itself.

The problem description

For people who haven't try it, I recommend you to try it first before opening the spoiler!

Spoiler

Full text and comments »

  • Vote: I like it
  • +35
  • Vote: I do not like it

By Misuki, 15 months ago, In English

Recently I am learning generating function and some application about it, and found out this algorithm is very elegant but seems to only be well-known in Japan, also I have nothing to do during lunar new year, so I decide to write a blog to share this algorithm with CF community!

edit: Actually this algorithm have been discussed before, you can also see the other explanation in the link of this comment.

If there have some mistake or question, please comment below to let me know :)

Prerequistes

  • FFT/NTT
  • basic understanding of generating function
  • basic understanding of linear recurrence
  • knowing how to compute inv of sparse formal power series in $$$O(nk)$$$

the connection between $$$\frac{P(x)}{Q(x)}$$$ and linear recurrence

In this section, I will show the relation between $$$\frac{P(x)}{Q(x)}$$$ and linear recurrence, by proving the following lemma.

lemma: A sequence $$$(a_n)_{n\ge 0}$$$ is linearly recurrent of order $$$d$$$ $$$\Leftrightarrow$$$ its generating function is $$$\frac{P(x)}{Q(x)}$$$ where $$$deg(P(x)) \le d - 1, deg(Q(x)) = d$$$.

$$$\Rightarrow$$$: By definition, we have $$$a_i = \sum\limits_{j = 1}^{d}c_j a_{i - j}$$$ for $$$i \ge d$$$, and let $$$A(x)$$$ be the power series of sequence $$$(a_n)_{n\ge 0}$$$, i.e., $$$A(x) = \sum\limits_{i = 0}^{\infty} a_i x^i$$$

Consider construct a polynomial $$$Q(x) = 1 - \sum\limits_{i = 1}^{d}c_i x^i$$$, let $$$P(x) = Q(x)A(x)$$$, then for the $$$i$$$-th term of $$$P(x)$$$ satisfy $$$i \ge d$$$, we have

$$$p_i = \sum\limits_{j = 0}^d q_j a_{i - j} = a_i - \sum\limits_{j = 1}^d c_j a_{i - j} = 0$$$

Since $$$p_i = 0$$$ for all $$$i \ge d$$$, we have $$$deg(P(x)) \le d - 1$$$, and obviously $$$deg(Q(x)) = d$$$. And since $$$q_0 = 1$$$, $$$Q(x)^{-1}$$$ exist, we can multiply $$$Q(x)^{-1}$$$ on both side of $$$P(x) = Q(x)A(x)$$$, given us $$$\frac{P(x)}{Q(x)} = A(x)$$$.

$$$\Leftarrow$$$: Similarly, consider multiply $$$Q(x)$$$ on both side of $$$\frac{P(x)}{Q(x)} = A(x)$$$, which give us $$$A(x)Q(x) = P(x)$$$, then again, consider $$$i$$$-th term of $$$P(x)$$$ for all $$$i \ge d$$$, we have

$$$p_i = 0 = a_i - \sum\limits_{j = 1}^d c_j a_{i - j} \Rightarrow a_i = \sum\limits_{j = 1}^d c_j a_{i - j}$$$

which imply sequence $$$(a_n)_{n\ge 0}$$$ is linearly recurrent of order $$$d$$$.

the algorithm

Given $$$P(x)$$$ and $$$Q(x)$$$ of the linear recurrence, Bostan-Mori try to find the $$$k$$$-th term of linear recurrence with the following inductive structure.

base case, $$$k = 0$$$

From the equation $$$P(x) = A(x)Q(x)$$$, we know $$$p_0 = a_0q_0 = a_0 = P(0)$$$, so it is just $$$P(0)$$$.

inductive step, $$$k \ge 1$$$

Consider multiply $$$\frac{P(x)}{Q(x)}$$$ with $$$Q(-x)$$$ on both denominator and numerator, which give us $$$\frac{P(x)Q(-x)}{Q(x)Q(-x)}$$$, consider the $$$t$$$-th term of $$$Q(x)Q(-x)$$$ for some odd $$$t$$$, which is $$$\sum\limits_{i + j = t \newline j \text{ is even}} q_i q_j + \sum\limits_{i + j = t \newline j \text{ is odd}} q_i (-q_j)$$$, we can see that they cancel each other, thus it is $$$0$$$, which means $$$Q(x)Q(-x)$$$ is a polynomial with only even terms, and there exist some $$$V(x^2) = Q(x)Q(-x)$$$.

Since $$$V(x^2)$$$ is a even polynomial, if $$$k$$$ is even(odd), then odd(even) terms of $$$P(x)Q(-x)$$$ is not important. Why? Let $$$U(x) = P(x)Q(-x)$$$, then the new linear recurrence will be $$$\frac{U(x)}{V(x^2)}$$$, where $$$deg(U(x)) \le 2d - 1, deg(V(x^2)) = 2d$$$, by the above lemma, this is a linear recurrence with order $$$2d$$$, and let try to derive the recurrence relation from the definition of $$$Q(x)$$$.

$$$V(x^2) = \sum\limits_{i = 0}^d v_i x_i^2 = Q(x)Q(-x) = 1 - \sum\limits_{i = 1}^d c'_{2i} x^{2i}$$$

We can see that $$$c'$$$ is the coefficient of the new linear recurrence, and only have non-zero coefficient in even terms, so if we want to compute $$$k$$$-th term of linear recurrence, we only need to know $$$k - 2, k - 4, k - 6...$$$ terms, and the terms with another parity will be useless, so we only need even(odd) term of $$$P(x)$$$.

So let try to split $$$U(x)$$$ into two polynomial with odd/even terms, $$$U_e(x) = \sum\limits_{i = 0}^{d - 1}u_{2i} x^i, U_o = \sum\limits_{i = 0}^{d - 1}u_{2i + 1} x^i$$$, then we have $$$\frac{P(x)Q(-x)}{Q(x)Q(-x)} = \frac{U(x)}{V(x^2)} = \frac{U_e(x^2) + xU_o(x^2)}{V(x^2)}$$$.

Finally, consider case working for parity of $$$k$$$, we have

$$$[x^k]\frac{U_e(x^2) + xU_o(x^2)}{V(x^2)} = \begin{cases} [x^k]\frac{U_e(x^2)}{V(x^2)} & \text{if } k \text{ is even} \\ [x^k]\frac{xU_o(x^2)}{V(x^2)} & \text{if } k \text{ is odd} \end{cases} = \begin{cases} [x^{\frac{k}{2}}]\frac{U_e(x)}{V(x)} & \text{if } k \text{ is even} \\ [x^{\frac{k - 1}{2}}]\frac{U_o(x)}{V(x)} & \text{if } k \text{ is odd} \end{cases}$$$

the implementation (psudo-code) and complexity analysis

Actually, it is no need to force $$$q_0 = 1$$$, we can let $$$q_0$$$ be any non-zero value, the above inductive step will still hold, which just need an little modification at base case, instead of returning $$$P(0)$$$, return $$$\frac{P(0)}{Q(0)}$$$.

Bostan-Mori(P, Q, k)
  while(k >= 1)
    U(x) = P(x)Q(-x)
    if k is even
      P(x) = U_e(x)
    else
      P(x) = U_o(x)
    V(x^2) = Q(x)Q(-x)
    Q(x) = V(x)
    k = floor(k/2)
  return P(0) / Q(0)

For each phrase, all we need to do is just FFT/NTT $$$O(1)$$$ times, and since after each phrase, $$$k$$$ will be divide by $$$2$$$, so there are $$$O(\lg k)$$$ phrases, and the time complexity is $$$O(d\lg d \lg k)$$$, where $$$d$$$ is the order the linear recurrence.

Finally, here is my implementation, though it is not very fast, it works.

compare with other algorithm

  • using matrix exponentiation can compute $$$k$$$-th term of linear recurrence in $$$O(d^3 \lg k)$$$, if multiply matrix naively.

  • using kitamasa method can compute $$$k$$$-th term of linear recurrence in $$$O(d^2 \lg k)$$$, or $$$O(d \lg d \lg k)$$$ using FFT/NTT.

reference

A Simple and Fast Algorithm for Computing the N-th Term of a Linearly Recurrent Sequence (original paper)

線形漸化的数列のN項目の計算 (blog written by Ryuhei Mori, one of the creator of this algorithm, written in Japanese)

Full text and comments »

  • Vote: I like it
  • +123
  • Vote: I do not like it

By Misuki, history, 2 years ago, In English

Recenetly I was learning Berlekamp-Massey and applying it when our dp can be seen as a linear recurrence, if you don't know how it works, here is an simple description of it.(or a more detail description in this blog)

simple description

And the question arise when I encounter this problem 506E — Mr. Kitayuta's Gift, I write a dp solution below.

Spoiler

Apparently, we can see $$$dp[i]$$$ as a $$$|s|^2$$$ times $$$1$$$ vector, which means the size of transition matrix will be $$$|s|^2$$$ times $$$|s|^2$$$, so according to Cayley-Hamilton theorem, the linear recurrence of this dp will have at most $$$|s|^2$$$ terms, so if we compute the first $$$2|s|^2$$$ vectors of $$$dp[i] (i \le 2|s|^2)$$$ then plug them into Berlekamp-Massey, calculate $$$dp[(n + |s|) / 2]$$$, the time complexity will be $$$O(26|s|^4 + |s|(|s|^2 + |s|^2lg(n+|s|))$$$, which obviously will not fit in the TL.

But it turns out that it will only have about $$$350$$$ terms at most, which is far from $$$|s|^2$$$, and will fit in the TL, you can see my submission. Here comes the question, do we have any method to estimate how many terms a linear recurrence have? If we don't, then how to determine the number of terms we need to compute to plug into Berlekamp-Massey?

btw, sorry for my bad english.

Full text and comments »

  • Vote: I like it
  • +19
  • Vote: I do not like it

By Misuki, history, 3 years ago, In English

Today I was solving pG in this problem list. When I submit my code it seems alright at the first few test cases but turns out to be an judgement fail. Does someone know the reason behind it?

picture

Here is my code:

code

UPD: The problem has already be fixed, and the code has been rejudged :D

Full text and comments »

  • Vote: I like it
  • +14
  • Vote: I do not like it