Алгоритм


14

Припустимо, нам задано різних цілих чисел , такі, що для деякої постійної , і для всіх .na1,a2,,an0aiknk>0i

Нам цікаво знайти підрахунок усіх можливих парних сум . ( дозволено).Sij=ai+aji=j

Один алгоритм полягає в тому, щоб побудувати поліном ступеня , і обчислити його квадрат за допомогою методу перетворення Фур'є і зчитувати повноваження з їх коефіцієнти в отриманому многочлені. Це алгоритм часу .P(x)=j=1nxajknO(nlogn)

У мене є два питання:

  • Чи існує алгоритм , який не використовує FFT?O(nlogn)

  • Чи відомі кращі алгоритми (тобто )? (FFT дозволено).o(нжурналн)


Чому важливо не використовувати FFT? Здається, у вас вже є гарне рішення вашої проблеми. Звідки випливає вимога не використовувати FFT? Це для мене звучить як досить неприродна вимога.
DW

@DW: Тому що тоді не буде запитання? :-) Мені просто цікаво знати, чи є інший підхід.
Арябхата

Добре, зрозумів! Зізнаюся, мені теж цікаво. :-) Дякую за цікаве запитання.
DW

@DW: Ласкаво просимо :-)
Ар'ябхата

Відповіді:


8

Здавалося б, ця проблема еквівалентна цілочисленному / многочленному квадратуванню:

1. Відомо, що множення полінома еквівалентно цілому множенню .

2. Очевидно, ви вже звели цю проблему до поліноміального / цілого квадратування; отже, ця проблема є не менш важкою, як квадрати.

Тепер я зменшу цілісні квадрати до цієї проблеми:

Припустимо, у вас був алгоритм:

F(a)P2(x),where P(x)=aiaxai

Цей алгоритм по суті є алгоритмом, про який ви запитуєте у своєму запитанні. Таким чином, якщо у мене був магічний алгоритм, який може це зробити, я можу зробити функцію, яка буде квадратним цілим числом y ( о так, я люблю mathjax: P ):SQUARE(y)y

Algorithm 1 Squaring1.:procedure SQUARE(y):2.:a() a starts as empty polynomial sequence3.:i04.:while y0 do break y down into a polynomial of base 25.:if y & 1 then if lsb of y is set6.:aai append i to a (appending xi)7.:end if8.:ii+19.:yy1 shift y right by one10.:end while11.:P2(x)F(a) obtain the squared polynomial via F(a)12.:return P2(2) simply sum up the polynomial13.:end procedure

Python ( тест з кодовою панеллю ):

#/cs//q/11418/2755

def F(a):
    n = len(a)
    for i in range(n):
        assert a[i] >= 0

    # (r) => coefficient
    # coefficient \cdot x^{r}
    S = {}
    for ai in a:
        for aj in a:
            r = ai + aj

            if r not in S:
                S[r] = 0

            S[r] += 1

    return list(S.items())

def SQUARE(x):
    x = int(x)

    a = []
    i = 0
    while x != 0:
        if x & 1 == 1:
            a += [i]
        x >>= 1
        i += 1

    print 'a:',a
    P2 = F(a)

    print 'P^2:',P2

    s = 0
    for e,c in P2:
        s += (1 << e)*c
    return s

3. Таким чином, квадратик є не менш важким, як ця проблема.

4. Тому ціле квадратування рівнозначно цій задачі. (кожен з них максимум такий же важкий, як один з одним, через ( 2 , 3 , 1 ))

O(nlogn)O(nlognloglogn)O(nlogn2O(logn))Ω(nlogn)

O(nlogn)

5. Тепер ваша проблема не є саме множенням, це квадратом. Тож квадратування простіше? Що ж, це відкрита проблема (поки що немає) : невідомо, що квадрати мають швидший алгоритм, ніж множення. Якщо ви могли знайти кращий алгоритм для своєї проблеми, ніж використання множення; то це, ймовірно, буде проривом.

O(nlogn)O(nlogn)O(nlogn)O(nlogn) або як найкращий алгоритм множення лише наближається до цієї складності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.