Nachia's blog

By Nachia, history, 3 months ago, In English

This is a topic on complexity analysis (for Round 975 Div. 1 E) with no special algorithm.

Problem

An integer sequence $$$(a _ 1,a _ 2,\ldots ,a _ n)$$$ is hidden. We know:

  • It is non-increasing. ( $$$a _ k\geq a _ {k+1}$$$ )
  • $$$0\leq a _ k\leq n/k$$$

Suppose we can get one value of $$$a _ k$$$ in $$$O(C)$$$ time. Find all values of $$$a _ 1,a _ 2,\ldots ,a _ n$$$ .

Algorithm

Put $$$a _ 0=n+1$$$ and $$$a _ {n+1}=0$$$ and call $$$\text{S} _ \text{EARCH}(1,n)$$$ . In a call of $$$\text{S} _ \text{EARCH}(l,r)$$$ , do nothing if $$$l\gt r$$$ . Also no more search is required if $$$a _ {l-1}=a _ {r+1}$$$ . Otherwise evaluate $$$a _ {\lfloor (l+r)/2\rfloor}$$$ and recursively call $$$\text{S} _ \text{EARCH}(l,\lfloor (l+r)/2\rfloor -1)$$$ and $$$\text{S} _ \text{EARCH}(\lfloor (l+r)/2\rfloor +1,r)$$$ .

A = [0] * (n+2)
A[0] = n+1
A[n+1] = 0

def f(k) :
    # find a_k

def search(l, r) :
    if l > r
        return
    if A[l-1] == A[r+1] :
        for x in range(l, r+1) :
            A[x] = A[l-1]
        return
    m = (l + r) // 2
    A[m] = f(m)
    search(l, m-1)
    search(m+1, r)

Complexity Analysis

I saw this algorithm in physics0523's blog post (https://physics0523.hatenablog.com/entry/2023/10/11/155814) and I suggested the complexity be probably $$$O(n+\sqrt{n}C)$$$ . Finally noshi91 made a proof(Twitter link) which says that is.

Only $$$O(2^{d/2})$$$ calls in depth $$$d$$$ .

Since the algorithm is just a binary search, searching space $$$[0,n+1)$$$ is splitted in $$$2^d$$$ segments with almost same sizes before it reaches depth $$$d$$$ . Especially the first one is $$$[0,\lfloor (n+1)/2^d \rfloor)$$$ .

Suppose $$$d$$$ is odd and set $$$d'=d-1$$$ . In depth $$$d'$$$ , the group of segments without the first $$$2^{d'/2}$$$ segments bounds $$$[\lfloor (n+1)/2^{d'/2} \rfloor ,n+1)$$$ . For $$$n/2^{d'/2}\leq x\leq n$$$ we have $$$a _ x\leq 2^{d'/2}$$$ so we need to search only $$$3\times 2^{d'/2}+1$$$ segments in depth $$$d$$$ .

For the case with even $$$d$$$ , we have no more calls than twice as depth-$$$(d-1)$$$ calls.


Since $$$\displaystyle \sum _ {d=0} ^ {\lceil \log _ 2 n \rceil} 2^{d/2} $$$ is bounded as $$$O(\sqrt{n})$$$ , the processing time overall is $$$O(n+\sqrt{n}C)$$$ .

Bonus

We can process the Decremental Predecessor Query Problem in amortized $$$O(1)$$$ time per query. For Round 975 Div. 1 E , we can use that instead of a general DSU to solve the entire task in $$$O(n\sqrt{n})$$$ time. Submission 283309295

Full text and comments »

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

By Nachia, history, 14 months ago, In English

I got AC on Codeforces Round 905 (Div. 1) C. Minimum Array with my prewritten code sorting all arrays obtained (in lexicographic order) in $$$\mathcal{O}(n\log n + q\log q)$$$ time.

https://mirror.codeforces.com/contest/1887/submission/229244614

How is the processing time achieved? I made a tutorial (in Japanese) before. (https://www.mathenachia.blog/sortseqs/ and https://nachiavivias.github.io/cp-library/cpp/array/point-update-lex-sort.html) This time I make a brief explanation in English.

Problem

First you are given an array $$$(A _ 0[0],A _ 0[1],\ldots ,A _ 0[N-1])$$$ of length $$$N$$$ . You will construct other $$$Q$$$ arrays $$$A _ 1, A _ 2, \ldots , A _ Q$$$ as follows :

  • For $$$k=1,2,\ldots ,Q$$$ (in order) , you are given an integer $$$p _ k$$$ $$$( 0 \leq p _ k \leq N - 1 )$$$ and a value $$$x _ k$$$ . Overwrite $$$A _ k$$$ with the copy of $$$A _ {k-1}$$$ and change the value of $$$A _ {k}[p _ k]$$$ to $$$x _ k$$$ .

Find an array $$$(F _ 0,F _ 1,F _ 2,\ldots ,F _ Q)$$$ of nonnegative integers such that :

  • $$$F _ i \lt F _ j \iff A _ i\lt A _ j$$$ (in lexicographic order) holds for $$$0 \leq i \leq Q$$$ , $$$0 \leq j \leq Q$$$ .
  • Maximum value of $$$(F _ 0,F _ 1,F _ 2,\ldots ,F _ Q)$$$ is minimized.

In other words, sort all $$$Q+1$$$ arrays in lexicographic order.

Algorithm

Above I wrote like $$$A _ a[b]$$$ , so I call $$$a$$$ as time index and $$$b$$$ as array index .

Divide and Conquer array index . After we could sort every half, we can get full answer in linear time with radix sort (sort by second digit, then stable sort by first digit) .

When we divide array index, changing points are also divided in two groups. So we can compress time index . We can bound the sum of number of time index as $$$\mathcal{O}(N+Q)$$$ in any layer of dividing. Of cource the number of the layers is $$$\mathcal{O}(\log N)$$$ . Therefore the entire process takes $$$\mathcal{O}((N+Q) \log (N+Q))$$$ time ( the term $$$Q\log Q$$$ is for sorting given values ).

Main Usage

We can sometimes use this deterministic algorithm instead of randomized hash.

Supplement Based on Comments

Thank you for your helpful comments.

Full text and comments »

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