Вирішити це можна досить ефективно, обчислюючи всі парні gcd, видаляючи дублікати, а потім повторюючи. Цей акт видалення дублікатів перед повторним повторенням робить його ефективним.
Я поясню алгоритм більш докладно нижче, але спочатку він допомагає визначити двійковий оператор . Якщо S , T - множини натуральних чисел, визначте⊗S, Т
S⊗ Т= { gcd ( s , t ) : s ∈ S, t ∈ T} .
Зауважте, що та | S ⊗ T | ≤ 10 9 (у вашій проблемі); як правило, S ⊗ T буде ще меншим, ніж будь-який із запропонованих меж, що допомагає зробити алгоритм ефективним. Також зазначимо, що ми можемо обчислити S ⊗ T за допомогою | S | × | Т | операції gcd шляхом простого перерахування.| S⊗ Т| ≤ | S| × | Т|| S⊗ Т| ≤ 109S⊗ ТS⊗ Т| S| × | Т|
З цим позначенням, ось алгоритм. Нехай - вхідний набір чисел. Обчисліть S 2 = S 1 ⊗ S 1 , потім S 3 = S 1 ⊗ S 2 , потім S 4 = S 1 ⊗ S 3 тощо. Знайдіть найменший k такий, що 1 ∈ S k, але 1 ∉ S k - 1 . Тоді ви знаєте, що розмір найменшого такого підмножини дорівнює kS1S2= S1⊗ S1S3= S1⊗ S2S4= S1⊗ S3к1 ∈ Sк1 ∉ Sk - 1к. Якщо ви також хочете вивести конкретний приклад такого підмножини, зберігаючи вказівники, ви можете легко реконструювати такий набір.
Це буде відносно ефективно, оскільки жоден з проміжних наборів не збільшується в розмірі вище (насправді, їх розмір, ймовірно, буде набагато меншим за цей), а час роботи вимагає приблизно 500 × ( | S 1 | + | S 2 | + ⋯ ) операції gcd.109500 × ( | S1| +|S2| +⋯)
Ось оптимізація, яка може ще більше підвищити ефективність. В основному, ви можете використовувати ітераційне подвоєння, щоб знайти найменший такий, що 1 ∈ S k . Зокрема, для кожного елемента x ∈ S i ми відслідковуємо найменший підмножину S 1 , gcd якого x та розмір якого ≤ i . (Видаляючи дублікати, ви вирішуєте зв'язки на користь меншої підмножини.) Тепер, а не обчислюйте послідовність дев'яти наборів S 1 , S 2 , S 3 , S 4 ,к1 ∈ Sкx ∈ SiS1х≤i , замість цього обчислюємо послідовність п’яти множин S 1 , S 2 , S 4 , S 8 , S 9 , обчислюючи S 2 = S 1 ⊗ S 1 , потім S 4 = S 2 ⊗ S 2 , потім S 8 = S 4 ⊗ S 4 , тоді S 9 = S 1 × S 8S1,S2,S3,S4,…,S9S1,S2,S4,S8,S9S2=S1⊗S1S4=S2⊗S2S8=S4⊗S4S9=S1×S8. Під час руху знайдіть перший таким, що 1 ∈ S k . Як тільки ви знайдете k таким, що 1 ∈ S k , ви можете негайно зупинитися: ви можете знайти найменший підмножина, gcd якого 1 , переглянувши підмножину, пов'язану з 1 . Отже, ви можете зупинитися, як тільки досягнете множини S k таким, що 1 ∈ S k , що дозволяє зупинитися рано, якщо ви знайдете менший підмножина.k∈[1,2,4,8,9]1∈Skk1∈Sk11Sk1∈Sk
Це має бути економічно ефективним та просторовим. Щоб заощадити простір, для кожного елемента вам не потрібно зберігати весь набір: достатньо для зберігання двох опорних покажчиків (щоб два елементи S i , S j, які ви взяли gcd, отримали x ) і необов'язково розмір відповідного підмножини.x∈SkSi,Sjx
В принципі, ви можете замінити послідовність будь-яким іншим ланцюгом додавання . Я не знаю, чи буде якийсь інший ланцюжок додавання кращим. Оптимальний вибір може залежати від розподілу правильних відповідей та очікуваних розмірів множин S k , що мені не зрозуміло, але, ймовірно, може бути отримане емпіричним шляхом шляхом експерименту.[1,2,4,8,9]Sk
Подяки: Дякую KWillets за ідею зберігати підмножину чисел разом з кожним елементом , що дозволяє зупинятись на ранніх термінах .Si