Идеальные номерные знаки


33

Идеальные номерные знаки

Начав несколько лет назад, я немного поиграл, катаясь на машине: проверяя, являются ли соседние номерные знаки «идеальными». Это относительно редко, но захватывающе, когда вы его найдете.

Чтобы проверить, является ли номерной знак идеальным:

  1. Суммируйте символы: A = 1, B = 2, ... Z = 26.
  2. Возьмите каждый последовательный кусок цифр и сложите их; умножьте каждую из этих сумм вместе.

Если значения в части 1 и части 2 равны, поздравляем! Вы нашли идеальный номерной знак!

Примеры

License plate: AB3C4F

Digits -> 3 * 4 
        = 12
Chars  -> A + B + C + F 
        = 1 + 2 + 3 + 6 
        = 12
12 == 12 -> perfect!


License plate: G34Z7T

Digits -> (3 + 4) * 7 
        = 49
Chars  -> G + Z + T 
        = 7 + 26 + 20 
        = 53
49 != 53 -> not perfect!


License plate: 10G61

Digits -> (1 + 0) * (6 + 1)
        = 7
Chars  -> G
        = 7
7 == 7 -> perfect!

Соревнование

Я использовал номерные знаки длиной 5 и 6 в качестве примеров, но эта процедура действительна для любой длины номерного знака. Ваша задача для заданной длины N вернуть количество идеальных номерных знаков этой длины. Для целей конкурса действительный номерной знак представляет собой любую комбинацию цифр 0-9 и символов AZ. Табличка должна содержать как символ, так и цифру, чтобы считаться потенциально совершенной. Для проверки, вот значения, которые я получил (хотя я не могу быть на 100% об их правильности, хахаха)

N < 2: 0
N = 2: 18
N = 3: 355
N = 4: 8012 

Заметки

Если каким-то образом это упрощает проблему на вашем языке, вы можете вывести пропорцию идеальных номерных знаков для данного N, по крайней мере, до 2 значащих цифр.

N < 2: 0
N = 2: 0.0138888...
N = 3: 0.0076088...
N = 4: 0.0047701...

ИЛИ, вы можете вывести эквивалентное значение мод 256

N < 2: 0
N = 2: 18
N = 3: 99
N = 4: 76

Кратчайшие победы!


2
Добро пожаловать на сайт! Я думаю, что это хороший вызов, но дополнительные разрешенные результаты затрудняют получение ответов. PPCG ищет объективные критерии победы, и это трудно сделать, когда существует так много свобод; это не только меняет формат вывода, это фактически меняет то, что вам разрешено выводить. Я бы порекомендовал отредактировать другие параметры и просто сделать так, чтобы количество выходных номеров было идеальным N.
HyperNeutrino

11
Лично мне бы больше понравился этот вызов, если бы он просто проверял, является ли данный номерной знак идеальным или нет (особенно потому, что у вас нет точных цифр для тестовых случаев. Хотя, вероятно, это нормально, пока потенциальные результаты вычисляются снижается. Не уверен, что другие люди чувствуют, хотя. Хорошая идея, хотя!
MildlyMilquetoast

4
Я согласен с Мистой Фиггинс; Я чувствую, что таким образом, это больше о поиске шаблона, который все еще является интересной задачей, но я думаю, что он может привлечь больше ответов, если бы это была просто проверка правильности. Хороший вызов, хотя!
HyperNeutrino

1
Я опубликовал тесно связанный вызов , надеясь, что он привлечет внимание к этому замечательному вопросу, а также немного упростит его, проверяя только (почти) идеальный номерной знак.
г-н Xcoder

1
@carusocomputing Я старался изо всех сил, но оказался пустым. Я отправил его своему учителю математики, и он пока пуст
Кристофер

Ответы:


9

Python 3.6, 150 байт

f=lambda n,t=-1,p=-1,a=0:sum(f(n-1,*((t,c+p*(p>=0),a),((t<0 or t)*(p<0 or p),-1,a-c))[c<0])for c in range(-26,10))if n else 0<(t<0 or t)*(p<0 or p)==a

полученные результаты:

f(2) = 18
f(3) = 355
f(4) = 8012
f(5) = 218153

Неуправляемая версия с объяснением:

digits=[*range(10)]
letters=[*range(1,27)]

def f(n, dt=-1, dp=-1, lt=0):
    if n:
        for d in digits:
            yield from f(n - 1,
                         dt,
                         d if dp < 0 else dp + d,
                         lt
                         )

        for l in letters:
            yield from f(n - 1,
                         dp if dt < 0 else dt if dp < 0 else dt*dp,
                         -1,
                         lt + l
                         )
    else:
        yield 0 < lt == (dt<0 or dt)*(dp<0 or dp)

Проблема сводится к поиску дерева, в котором каждый уровень дерева соответствует позиции в номере автомобильного номера, а каждый узел имеет 36 дочерних элементов (10 цифр и 26 букв). Функция выполняет рекурсивный поиск дерева, накапливая значения для цифр и букв в процессе работы.

n is the number of levels to search. 
dp accumulates the sum of a group of digits.
dt accumulates the product of the digit sums.
lt accumulates the sum of the letter values.

For dp and dt, a value < 0 indicates it is not initialized.

Гольф включен, преобразование циклов for в суммы генераторов:

sum(f(n-1, 
      dt,
      d if dp < 0 else dp + d,
      lt) for d in digits)
+
sum(f(n-1,
      dp if dt<0 else dt if dp<0 else dt*dp,
      -1,
      lt+l) for l in letters)

Затем объединяем генераторы. Кодируйте буквы от A до Z от -1 до -26 и цифры от 0 до 9. Таким образом, сумма становится:

sum(f(n-1, *args) for c in range(-26, 10)),

где args это:

((dp if dt<0 else dt if dp<0 else dt*dp, -1, lt-l) if c <0 else
 (dt, d if dp<0 else dp+d, lt))

Остальная часть игры в гольф - это преобразование функции в лямбду, сокращение имен переменных и упрощение выражений.


Это красноречивое решение, каким будет время выполнения? n*n*log(n)или что-то подобное?
Волшебная урна осьминога

@carusocomputing Спасибо. Решение все еще генерирует все возможные перестановки заданной длины, поэтому оно имеет ту же сложность, что и другие решения. Что-то вроде k ** n, где k - это количество символов в алфавите (например, 10 цифр + 26 букв = 36), а n - это количество символов на номерном знаке. Выполнение этого для n = 5 требует проверки 36 ^ 5 = 60 466 176 перестановок и занимает минуту или две (запоминание может ускорить его, но будет стоить много байтов ;-)).
RootTwo

6

Дьялог АПЛ, 57 56 байт

+/(+/0⌈a-9)=×/c*⍨-2-/0,⌈\(+\a×b)×c←2>/0,⍨b←9≥a←↑1↓,⍳⎕⍴36

(предполагается, что ⎕io←0 )

a матрица всех действующих номерных знаков (кроме 00...0 ), закодированная: 0-9 для цифр, 10-35 для букв

b битовая маска для того, где встречаются цифры

c битовая маска для последней цифры в каждой группе последовательных цифр


Попробуйте онлайн для 1-4, нужно больше памяти для 4, но есть и способы обойти это!
Адам

4

Python 2, 359 295 байт

Довольно долго; это тривиальное решение. Я уверен, что это правильно, хотя это не соответствует контрольным случаям в тесте. Решения, которые я получаю, соответствуют ответам Дада.

import itertools as i,re as r,string as s
print len([''.join(x)for x in i.product(s.lowercase+s.digits,repeat=input())if(lambda t:r.search('\\D',t)and r.search('\\d',t)and reduce(int.__mul__,[sum(map(int,k))for k in r.split('\\D+',t)if k])==sum([k-96 for k in map(ord,t) if k>96]))(''.join(x))])

-64 байта благодаря предложениям от @numbermaniac


1
Вы можете сохранить около трех байтов в c (x) и последней строке; удалить пробел между 96 и for; между map(ord,x)и if; и в последней строке, между .join(x)и for. Я думаю, вы также можете сэкономить еще больше, если переопределите функции в лямбдах.
Numbermaniac

@numbermaniac Спасибо! (Всего 64 байта)
HyperNeutrino

4

Python 2 , 291 287 276 273 байта

lambda n:sum(1for x in s.product(y+z,repeat=n)if(lambda p,s=set:reduce(int.__mul__,[sum(map(int,i))for i in re.findall(r"\d+",p)],1)==sum(ord(i)-64for i in p if ord(i)>64)and s(p)&s(y)and s(p)&s(z))(''.join(x)))
import re,itertools as s,string as t
y=t.uppercase
z=t.digits

Попробуйте онлайн!


Полученные результаты:

0 0
1 0
2 18
3 355
4 8012

3

Perl 5 , 117 байт

116 байт кода + -pфлаг.

$"=",";@F=(A..Z,0..9);map{$r=1;$r*=eval s/./+$&/gr for/\d+/g;$r+=64-ord for/\pl/g;$\+=!$r*/\pl/*/\d/}glob"{@F}"x$_}{

Попробуйте онлайн!

Это кажется довольно неоптимальным, но у меня сейчас нет идей.
Сам код очень неэффективен, поскольку он вычисляет каждую перестановку a..z,0..9длины n(это занимает примерно 1 секунду n=3, ~ 15 секунд n=4и ~ 7 минут n=5).
Алгоритм довольно прост: для каждой возможной таблички размера n(сгенерированной с glob"{@F}"x$_- globоператор довольно волшебен) $r*=eval s/./+$&/gr for/\d+/g;вычисляет произведение каждого куска цифр и $r+=64-ord for/\pl/gвычитает из него вес букв. Затем мы увеличиваем счетчик, $\если $ris 0( !$r) и если табличка содержит цифры и буквы ( /\pl/*/\d/). $\неявно печатается в конце благодаря -pфлажку.

Обратите внимание , что номер я получаю является n=2 -> 18, n=3 -> 355, n=4 -> 8012, n=5 -> 218153. Я уверен, что это правильные, но я могу ошибаться, в этом случае дайте мне знать, и я удалю этот ответ.


3

APL (Dyalog) , 71 байт

Полное тело программы. Подсказки для N. N≥4 требуют огромных объемов памяти и вычислений.

+/((+/⊢⍳∩)∘⎕A=(×/'\d+'S{+/⍎¨⍵.Match}))¨l/⍨∧⌿∨/¨c∘.∊l←,(∊c←⎕DA)∘.,⍣⎕⊂⍬

Попробуйте онлайн!


2

Scala, 265 байт

(n:Int)=>{val i=('A'to'Z')++('0'to'9');Seq.fill(n)(i).flatten.combinations(n).flatMap(_.permutations).map(_.mkString).count(l=>"(?=.*[A-Z])(?=.*\\d)".r.findAllIn(l).size>0&&l.map(_-64).filter(_>0).sum==l.split("[A-Z]").filter(""<).map(_.map(_-48).sum).reduce(_*_))}

Пояснения:

(n:Int) => {
    val i = ('A' to 'Z') ++ ('0' to '9');                       // All license plates available characters.
    Seq.fill(n)(i).flatten                                      // Simulate combination with repetition (each character is present n times)
        .combinations(n)                                        // and generate all combinations of size n (all license plates).
        .flatMap(_.permutations)                                // For each combination, generate all permutations (ex. : Seq('A', '1') => Seq('A', '1') and Seq('1', 'A')), and
        .map(_.mkString)                                        // convert each permutation to String (Seq('A', '1') => "A1").
        .count ( l =>                                           // Then count all strings having :
            "(?=.*[A-Z])(?=.*\\d)".r.findAllIn(l).size > 0 &&   // at least 1 character and 1 digit and
            l.map(_ - 64).filter(_ > 0).sum ==                  // a sum of characters (> 'A' or > 64) equals to
            l.split("[A-Z]").filter(""<)
                .map(_.map(_ - 48).sum)
                .reduce(_*_)                                    // the product of sum of digits groups (split String by letters to get digits groups)
        )
}

Заметки :

  • -64и -48используются для преобразования Char(соответственно буквы и цифры) , его Intзначение ( 'A' - 64 = 1, 'B' - 64 = 2..., '9' - 48 = 9)
  • Фильтр l.split("[A-Z]").filter(""<)используется для исключения ""значений, если lначинается с буквы (пример:) "A1".split("[A-Z]") => Array("", 1). Там может быть лучшее и более короткое решение

Тестовые случаи:

val f = (n:Int) => ...  // assign function
(1 to 5).foreach ( i =>
    println(s"N = $i: ${f(i)}")
)

Полученные результаты :

N = 1: 0
N = 2: 18
N = 3: 355
N = 4: 8012
N = 5: 218153

Функция довольно медленная, n > 4поскольку все комбинации должны быть сгенерированы.


2

Java, 382 365 байт

  • Сохранено 17 байт, благодаря Кевину Круйссену

Golfed

int h(String s){int m=0;for(int c:s.toCharArray())m+=c-48;return m;}
int g(String t){int d=1,c=0;for(String s:t.split("[^0-9]"))d*=h(s);for(String s:t.split("[^A-Z]"))c+=s.charAt(0)-65;return d==c?1:0;}
int f(String t,int n){int m=0;if(t.length()==n)return g(t);for(int d=48;d<58;)m+=f(t+d++,n);for(int c=65;c<91;)m+=f(t+c++,n);return m;}
int s(int n){return f("",n);}

Детальнее

// return sum of adjecent digits
int h(String s)
{
    int sum = 0;
    for(char c : s.toCharArray()) sum += c-'0';
    return sum;
}

// check if perfect
int g(String t)
{
    int d = 1;
    int c = 0;

    for(String s : t.split("[^0-9]")) d *= h(s);
    for(String s : t.split("[^A-Z]")) c += s.charAt(0)-'A';

    return d == c ? 1 : 0;
}

// tree of enumerations
int f(String t, int n)
{
    // base case
    if(t.length() == n)
    {
        return g(t);
    }

    // enumeration
    int sum = 0;
    for(char d='0'; d<='9'; d++) sum += f(t+d, n);
    for(char c='A'; c<='Z'; c++) sum += f(t+c, n);

    return sum;
}

int s(int n){ return f("",n); }

Я думаю, что вам нужна функция, которая принимает только в nкачестве входных данных.
Кристиан Сиверс

@ChristianSievers исправлено
Khaled.K

1
Некоторые вещи для игры в гольф для вашего текущего кода: int h(String s){int m=0;for(int c:s.toCharArray())m+=c-48;return m;}int g(String t){int d=1,c=0;for(String s:t.split("[^0-9]"))d*=h(s);for(String s:t.split("[^A-Z]"))c+=s.charAt(0)-65;return d==c?1:0;}int f(String t,int n){int m=0;if(t.length()==n)return g(t);for(int d=48;d<58;)m+=f(t+d++,n);for(int c=65;c<91;)m+=f(t+c++,n);return m;}int s(int n){return f("",n);}( 365 байт ) Вы можете сравнить свою текущую версию с этой, чтобы увидеть изменения, которые я сделал (слишком много, чтобы поместиться в оставшейся части этого комментария). :)
Кевин Круйссен

@KevinCruijssen спасибо, 17 байт сейчас
Халед.К

2

GAP , 416 байт

Не выиграет от размера кода, и далеко от постоянного времени, но использует математику для ускорения!

x:=X(Integers);
z:=CoefficientsOfUnivariatePolynomial;
s:=Size;

f:=function(n)
 local r,c,p,d,l,u,t;
 t:=0;
 for r in [1..Int((n+1)/2)] do
  for c in [r..n-r+1] do
   l:=z(Sum([1..26],i->x^i)^(n-c));
   for p in Partitions(c,r) do
    d:=x;
    for u in List(p,k->z(Sum([0..9],i->x^i)^k)) do
     d:=Sum([2..s(u)],i->u[i]*Value(d,x^(i-1))mod x^s(l));
    od;
    d:=z(d);
    t:=t+Binomial(n-c+1,r)*NrArrangements(p,r)*
         Sum([2..s(d)],i->d[i]*l[i]);
   od;
  od;
 od;
 return t;
end;

Чтобы выжать ненужные пробелы и получить одну строку с 416 байтами, пройдите через это:

sed -e 's/^ *//' -e 's/in \[/in[/' -e 's/ do/do /' | tr -d \\n

Мой старый ноутбук, «разработанный для Windows XP», может рассчитать f(10)менее чем за одну минуту и ​​пойти гораздо дальше в течение часа:

gap> for i in [2..15] do Print(i,": ",f(i),"\n");od;
2: 18
3: 355
4: 8012
5: 218153
6: 6580075
7: 203255386
8: 6264526999
9: 194290723825
10: 6116413503390
11: 194934846864269
12: 6243848646446924
13: 199935073535438637
14: 6388304296115023687
15: 203727592114009839797

Как это работает

Предположим, что сначала мы хотим узнать только количество идеальных номерных знаков, соответствующих шаблону LDDLLDL, где Lобозначает букву и Dцифру. Предположим, у нас есть список lчисел, который l[i]дает количество способов, которыми буквы могут дать значение i, и аналогичный список dдля значений, которые мы получаем из цифр. Тогда число совершенных номерных знаков с общей стоимостью iбудет справедливым l[i]*d[i], и мы получим количество всех совершенных номерных знаков с нашим шаблоном, суммируя это по всем i. Давайте обозначим операцию получения этой суммы l@d.

Теперь, даже если лучший способ получить эти списки - это попробовать все комбинации и сосчитать, мы можем сделать это независимо для букв и цифр, рассматривая 26^4+10^3случаи вместо 26^4*10^3 случаев, когда мы просто пробегаем все таблички, соответствующие шаблону. Но мы можем сделать намного лучше: lэто просто список коэффициентов, (x+x^2+...+x^26)^kгде kчисло букв, здесь4 .

Точно так же мы получаем количество способов получить сумму цифр в серии kцифр как коэффициенты (1+x+...+x^9)^k. Если имеется более одного набора цифр, нам нужно объединить соответствующие списки с операцией d1#d2, в iкоторой в качестве значения в качестве суммы принимается сумма всех d1[i1]*d2[i2]где . Вместе с тем, что он является билинейным, это дает хороший (но не очень эффективный) способ его вычисления.i1*i2=i . Это свертка Дирихле, которая является просто произведением, если мы интерпретируем списки как коэффициенты рядов Дирхлета. Но мы уже использовали их как полиномы (конечные степенные ряды), и нет хорошего способа интерпретировать операцию для них. Я думаю, что это несоответствие является частью того, что затрудняет поиск простой формулы. Давайте все равно будем использовать его на полиномах и использовать те же обозначения #. Легко вычислить, когда один операнд является мономом: мы имеемp(x) # x^k = p(x^k)

Обратите внимание, что kбуквы дают значение самое большее 26k, в то время как k однозначные числа могут давать значение 9^k. Таким образом, мы часто получим ненужные высокие полномочия в dполиноме. Чтобы избавиться от них, мы можем вычислить по модулю x^(maxlettervalue+1). Это дает большую скорость и, хотя я не сразу заметил, даже помогает в гольф, потому что теперь мы знаем, что степень dне больше, чем l, что упрощает верхний предел в финале Sum. Мы получаем еще большее ускорение, выполняя modвычисления в первом аргументе Value (см. Комментарии), а выполнение всего #вычисления на более низком уровне дает невероятное ускорение. Но мы все еще пытаемся быть законным ответом на проблему игры в гольф.

Итак, мы получили l и dи их можно использовать для вычисления количества совершенных номерных знаков с рисунком LDDLLDL. Это тот же номер, что и для шаблона LDLLDDL. В общем, мы можем изменить порядок серий цифр разной длины, сколько захотим, NrArrangementsдает количество возможностей. И хотя между рядами цифр должна быть одна буква, остальные буквы не являются фиксированными. BinomialСчитает эти возможности.

Теперь осталось пройти через все возможные способы получения длин серийных цифр. rпробегает все числа пробегов, cвсе общее количество цифр и pвсе разделы cс rслагаемыми.

Общее количество разделов, на которые мы смотрим, на два меньше, чем количество разделов n+1, и функции разделов растут примерно так exp(sqrt(n)). Таким образом, хотя все еще существуют простые способы улучшить время выполнения путем повторного использования результатов (работа с разделами в другом порядке), для фундаментального улучшения нам следует избегать отдельного рассмотрения каждого раздела.

Быстро вычислить

Обратите внимание, что (p+q)@r = p@r + q@r. Само по себе это просто помогает избежать некоторых умножений. Но вместе с (p+q)#r = p#r + q#rэтим означает, что мы можем объединить путем простого сложения полиномы, соответствующие разным разбиениям. Мы не можем просто добавить их все, потому что нам все еще нужно знать, с какимиl нам нужно @объединить, какой фактор мы должны использовать, и какие #расширения все еще возможны.

Давайте объединим все полиномы, соответствующие разделам с одинаковой суммой и длиной, и уже учтем несколько способов распределения длин серий цифр. В отличие от того, что я размышлял в комментариях, мне не нужно заботиться о наименьшем используемом значении или о том, как часто оно используется, если я буду уверен, что не буду расширять это значение.

Вот мой код C ++:

#include<vector>
#include<algorithm>
#include<iostream>
#include<gmpxx.h>

using bignum = mpz_class;
using poly = std::vector<bignum>;

poly mult(const poly &a, const poly &b){
  poly res ( a.size()+b.size()-1 );
  for(int i=0; i<a.size(); ++i)
    for(int j=0; j<b.size(); ++j)
      res[i+j]+=a[i]*b[j];
  return res;
}

poly extend(const poly &d, const poly &e, int ml, poly &a, int l, int m){
  poly res ( 26*ml+1 );
  for(int i=1; i<std::min<int>(1+26*ml,e.size()); ++i)
    for(int j=1; j<std::min<int>(1+26*ml/i,d.size()); ++j)
      res[i*j] += e[i]*d[j];
  for(int i=1; i<res.size(); ++i)
    res[i]=res[i]*l/m;
  if(a.empty())
    a = poly { res };
  else
    for(int i=1; i<a.size(); ++i)
      a[i]+=res[i];
  return res;
}

bignum f(int n){
  std::vector<poly> dp;
  poly digits (10,1);
  poly dd { 1 };
  dp.push_back( dd );
  for(int i=1; i<n; ++i){
    dd=mult(dd,digits);
    int l=1+26*(n-i);
    if(dd.size()>l)
      dd.resize(l);
    dp.push_back(dd);
  }

  std::vector<std::vector<poly>> a;
  a.reserve(n);

  a.push_back( std::vector<poly> { poly { 0, 1 } } );
  for(int i=1; i<n; ++i)
    a.push_back( std::vector<poly> (1+std::min(i,n+i-i)));
  for(int m=n-1; m>0; --m){
    //    std::cout << "m=" << m << "\n";
    for(int sum=n-m; sum>=0; --sum)
      for(int len=0; len<=std::min(sum,n+1-sum); ++len){
        poly d {a[sum][len]} ;
        if(!d.empty())
          for(int sumn=sum+m, lenn=len+1, e=1;
              sumn+lenn-1<=n;
              sumn+=m, ++lenn, ++e)
            d=extend(d,dp[m],n-sumn,a[sumn][lenn],lenn,e);
      }
  }
  poly let (27,1);
  let[0]=0;
  poly lp { 1 };
  bignum t { 0 };
  for(int sum=n-1; sum>0; --sum){
    lp=mult(lp,let);
    for(int len=1; len<=std::min(sum,n+1-sum); ++len){
      poly &a0 = a[sum][len];
      bignum s {0};
      for(int i=1; i<std::min(a0.size(),lp.size()); ++i)
        s+=a0[i]*lp[i];
      bignum bin;
      mpz_bin_uiui( bin.get_mpz_t(), n-sum+1, len );
      t+=bin*s;
    }
  }
  return t;
}

int main(){
  int n;
  std::cin >> n;
  std::cout << f(n) << "\n" ;
}

Это использует библиотеку GNU MP. На Debian установите libgmp-dev. Компилировать с g++ -std=c++11 -O3 -o pl pl.cpp -lgmp -lgmpxx. Программа берет свой аргумент из стандартного ввода. Для выбора времени используйтеecho 100 | time ./pl .

В конце a[sum][length][i]приводится количество способов, которыми sum цифры в lengthпрогонах могут дать номер i. Во время вычислений, в начале mцикла, он дает число способов, которые могут быть выполнены с числами, превышающимиm . Все начинается с a[0][0][1]=1. Обратите внимание, что это расширенный набор чисел, которые нам нужны для вычисления функции для меньших значений. Таким образом, почти одновременно мы можем вычислить все значения до n.

Нет рекурсии, поэтому у нас есть фиксированное количество вложенных циклов. (Самый глубокий уровень вложенности равен 6.) Каждый цикл проходит через ряд значений, линейных в nхудшем случае. Так что нам нужно только полиномиальное время. Если мы посмотрим ближе на вложенные iи jциклы extend, мы найдем верхний предел для jформы N/i. Это должно дать только логарифмический коэффициент для jцикла. Внутренняя петля вf (с и sumnт. Д.) Похож. Также имейте в виду, что мы вычисляем с быстро растущими числами.

Обратите внимание, что мы храним O(n^3) эти числа.

Экспериментально я получаю эти результаты на разумном оборудовании (i5-4590S): f(50)требуется одна секунда и 23 МБ, f(100)требуется 21 секунда и 166 МБ, f(200)требуется 10 минут и 1,5 ГБ и f(300)один час и 5,6 ГБ. Это предполагает сложность времени лучше, чем O(n^5).


Так как это сложная задача для игры в гольф, этот ответ должен быть решен. Сожалею.
Rɪᴋᴇʀ

1
@Riker Хотя я и не думаю, что мой код был слишком многословным для начала, я немного поиграл в гольф и взял на себя бремя определения его размера, когда пробелы вытесняются.
Кристиан Сиверс

1
@carusocomputing Боюсь, это намного хуже. Я рассматриваю отдельно каждый случай распределения цифр между сериями цифр, например, есть одна серия из трех цифр, или есть одна серия из двух цифр и одна одна цифра, или есть три однозначные цифры, но для n=5, нет случай с двумя цифрами и двумя однозначными числами, потому что тогда у нас недостаточно букв для разделения чисел. Вот что делают три внешних forцикла: проходят через все полезные разделы чисел <n. (И я только что понял, что я также допускаю nцифры. По счастливой случайности другая оптимизация считает это 0).
Кристиан Сиверс

1
@carusocomputing Обратите внимание , что для чисел <n/2, все разделы полезны. А оставшиеся вычисления все еще занимают непостоянное время. Чтобы увидеть, что происходит, вы можете добавить Print(p,"\n");в начало тела for p...цикла. - У меня появилась идея использовать на один цикл меньше, но это поможет только размеру кода.
Кристиан Сиверс

2
Я получаю потрясающую скорость, переместив mod(что уже очень помогло) вValue , изменив его на Value(d mod x^(1+QuoInt(s(l)-1,i-1)),x^(i-1)). Одно это позволяет вычислить f(15)за 80 секунд.
Кристиан Сиверс

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.