Fibonacci Strings (Codeforces 1719E)
Tags: Greedy, number theory

In all schools in Buryatia, in the $$$1$$$ class, everyone is told the theory of Fibonacci strings."A block is a subsegment of a string where all the letters are the same and are bounded on the left and right by the ends of the string or by letters other than the letters in the block. A string is called a Fibonacci string if, when it is divided into blocks, their lengths in the order they appear in the string form the Fibonacci sequence ($$$f_0 = f_1 = 1$$$, $$$f_i = f_{i-2} + f_{i-1}$$$), starting from the zeroth member of this sequence. A string is called semi-Fibonacci if it possible to reorder its letters to get a Fibonacci string."Burenka decided to enter the Buryat State University, but at the entrance exam she was given a difficult task. She was given a string consisting of the letters of the Buryat alphabet (which contains exactly $$$k$$$ letters), and was asked if the given string is semi-Fibonacci. The string can be very long, so instead of the string, she was given the number of appearances of each letter ($$$c_i$$$ for the $$$i$$$-th letter) in that string. Unfortunately, Burenka no longer remembers the theory of Fibonacci strings, so without your help she will not pass the exam.

Input: The first line contains one integer $$$t$$$ ($$$1 \leq t \leq 10^4$$$) — the number of test cases. The following is a description of the input data sets.The first line of each test case contains one integer $$$k$$$ ($$$1 \leq k \leq 100$$$) — the number of letters in the alphabet.The second line of each test case contains $$$k$$$ integers $$$c_1, c_2, \ldots, c_k$$$ ($$$1 \leq c_i \leq 10^9$$$) — the number of occurrences of each letter in the string.

Output: For each test case print the string "YES" if the corresponding string is semi-Fibonacci, and "NO" if it is not.You can print "YES" and "NO" in any case (for example, the strings "yEs", "yes", "Yes" will be recognized as a positive answer).

Note: In the first test case, a one-character string is semi-Fibonacci, being itself a Fibonacci string.In the second test case, a string of two different characters is Fibonacci.In the third test case, the string "abb" (let the first of the alphabet letter be a, the second letter b) is not a semi-Fibonacci string, since no permutation of its letters ("abb", "bab", and "bba") is a Fibonacci string.In the fourth test case, two permutations of the letters of the string "abaccac" (the first letter is a, the second letter is b, the third letter is c) are Fibonacci strings — "abaaccc" and "cbccaaa".

Sample Inputs:
6
1
1
2
1 1
2
1 2
3
3 1 3
2
7 5
6
26 8 3 4 13 34

Sample Outputs:
YES
YES
NO
YES
NO
YES

Solution (Python):
import heapq
FIBNUM = 50
fibs = [1, 1]
for i in range(FIBNUM):
    fibs.append(fibs[-1] + fibs[-2])
fibs_sum = [1]
for num in fibs[1:]:
    fibs_sum.append(num + fibs_sum[-1])
fibs_sum_dict = dict()
for (idx, num) in enumerate(fibs_sum):
    fibs_sum_dict[num] = idx
t = int(input())
for _ in range(t):
    k = int(input())
    arr = input().split()
    arr = [int(i) for i in arr]
    arr_sum = sum(arr)
    if arr_sum not in fibs_sum_dict:
        print('NO')
    else:
        arr_heap = [-i for i in arr]
        heapq.heapify(arr_heap)
        idx = fibs_sum_dict[arr_sum]
        last_value = 0
        success = True
        while True:
            if len(arr_heap) == 0:
                success = False
                break
            value = -heapq.heappop(arr_heap)
            if value < fibs[idx]:
                success = False
                break
            if last_value > 0:
                heapq.heappush(arr_heap, -last_value)
            last_value = value - fibs[idx]
            idx -= 1
            if idx < 0:
                break
        if success:
            print('YES')
        else:
            print('NO')

Solution (Python):
def fibSeq(summation):
    x = []
    i = 0
    a = 0
    b = 0
    c = 1
    while i <= summation:
        if i == summation:
            return x
        a = b + c
        temp = a
        c = b
        b = temp
        i += a
        x.append(a)
    return x
import heapq
t = int(input())
for case in range(t):
    k = int(input())
    c = list(map(int, input().split()))
    summation = 0
    x = []
    x = fibSeq(sum(c))
    if sum(c) != sum(x):
        print('NO')
        continue
    c.sort()
    cT = c
    c = [-i for i in cT]
    heapq.heapify(c)
    index = -1
    lstVal = 0
    success = True
    for i in range(len(x) - 1, -1, -1):
        if not len(c):
            success = False
            break
        val = heapq.heappop(c)
        if -val < x[i]:
            success = False
            break
        if lstVal < 0:
            heapq.heappush(c, lstVal)
        lstVal = val + x[i]
        if not i:
            break
    if success:
        print('YES')
    else:
        print('NO')

Solution (Python):
import os
import sys
from io import BytesIO, IOBase
_str = str
str = lambda x=b'': x if type(x) is bytes else _str(x).encode()
BUFSIZE = 8192

class FastIO(IOBase):
    newlines = 0

    def __init__(self, file):
        self._fd = file.fileno()
        self.buffer = BytesIO()
        self.writable = 'x' in file.mode or 'r' not in file.mode
        self.write = self.buffer.write if self.writable else None

    def read(self):
        while True:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            if not b:
                break
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines = 0
        return self.buffer.read()

    def readline(self):
        while self.newlines == 0:
            b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
            self.newlines = b.count(b'\n') + (not b)
            ptr = self.buffer.tell()
            (self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
        self.newlines -= 1
        return self.buffer.readline()

    def flush(self):
        if self.writable:
            os.write(self._fd, self.buffer.getvalue())
            (self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

    def __init__(self, file):
        self.buffer = FastIO(file)
        self.flush = self.buffer.flush
        self.writable = self.buffer.writable
        self.write = lambda s: self.buffer.write(s.encode('ascii'))
        self.read = lambda : self.buffer.read().decode('ascii')
        self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def main():
    t = int(input())
    fib = [1, 1]
    while fib[-1] <= int(1000000000.0):
        fib.append(fib[-1] + fib[-2])
    fib.pop()

    def dfs(num, now, prev):
        if num == -1:
            return True
        for i in range(len(now)):
            if i != prev and now[i] >= fib[num]:
                now[i] -= fib[num]
                if dfs(num - 1, now, i):
                    return True
                now[i] += fib[num]
        return False
    while t:
        k = int(input())
        c = list(map(int, input().strip().split(' ')))
        vsum = sum(c)
        fib_sum = 0
        num = 0
        for i in range(len(fib)):
            fib_sum += fib[i]
            if fib_sum >= vsum:
                num = i
                break
        if k > len(fib) or fib_sum != vsum:
            print('NO')
        elif dfs(num, c, -1):
            print('YES')
        else:
            print('NO')
        t -= 1
    return
main()