ashktchm's blog

By ashktchm, history, 3 years ago, In English

I read somewhere that using collections.Counter is faster for getting the count of the elements in an array. Is this true?

If yes, can someone tell me why did 233131667 TLE while 233285899 using inbuild python dictionary get Accepted? I tried using collections.defaultdict which also gave TLE.

Apologies if I am missing something.

  • Vote: I like it
  • 0
  • Vote: I do not like it

»
3 years ago, hide # |
Rev. 2  
Vote: I like it +20 Vote: I do not like it

Python dictionaries are really frail, and if you know how they work, you can easily construct input data that makes them take O(n^2) time. The reason there was a difference between your submissions is because your code is different between the two submission. In the one that survived, you set cnt[1]=0, which broke the hack in test case 27 (since it relies on key=1 not being in the dictionary until the very end).

Here is an anti-hash hack generator for Python dictionaries (it supports CPython dicts, and PyPy dicts and sets)

def anti_hash_hack(n, x=1, cpython=False):
    """
    Input: integer n > 0
    Output: List A of length n 
    such that x <= A[i] <= x + 2**(n.bit_length() + 2)
    """
    pow2 = 2**(n.bit_length() + 2)
    
    A = [x + pow2]
    i = perturb = x
    while len(A) < n//2:
        A.append(i + pow2)
        if cpython:
            perturb >>= 5
        i = (5 * i + perturb + 1) % pow2
        if not cpython:
            perturb >>= 5
    
    while len(A) < n:
        A.append(x)
    
    return A

To generate a hack for both of your submissions, I had to make $$$x \ge 3$$$ since you have cnt[1] = 0 and cnt[2] = 0 in your code.

n = 2*10**5
A = anti_hash_hack(n, 3, False)
print(1)
print(n)
print(*A)