Блог пользователя Nachia

Автор Nachia, история, 2 месяца назад, По-английски

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

Полный текст и комментарии »

  • Проголосовать: нравится
  • +270
  • Проголосовать: не нравится

Автор Nachia, история, 13 месяцев назад, По-английски

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.

Полный текст и комментарии »

  • Проголосовать: нравится
  • +134
  • Проголосовать: не нравится