Perfect License Plates


33

Perfect License Plates

Começando há alguns anos, fiz um pequeno jogo enquanto dirigia: verificando se as placas próximas são "perfeitas". É relativamente raro, mas emocionante quando você encontra um.

Para verificar se uma placa é perfeita:

  1. Resuma os caracteres, com A = 1, B = 2, ... Z = 26.
  2. Pegue cada pedaço consecutivo de numerais e some-os; multiplique cada uma dessas somas.

Se os valores da parte 1 e da parte 2 forem iguais, parabéns! Você encontrou uma placa perfeita!

Exemplos

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!

O desafio

Eu usei placas de comprimento 5 e 6 como exemplos, mas esse procedimento é válido para qualquer comprimento de placa. Seu desafio é, para um determinado comprimento N, retornar o número de placas perfeitas desse comprimento. Para os propósitos do desafio, uma placa válida é qualquer combinação de dígitos de 0 a 9 e caracteres de AZ. A placa deve conter um caractere e um numeral para ser considerado potencialmente perfeito. Para fins de verificação, aqui estão os valores que obtive (embora eu não possa ter 100% de exatidão, hahaha)

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

Notas

Se, de alguma forma, isso simplificar o problema no seu idioma, você poderá gerar a proporção de placas perfeitas para um determinado N, com pelo menos 2 dígitos significativos.

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

OU, você pode emitir o valor equivalente mod 256

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

Vitórias mais curtas!


2
Bem vindo ao site! Penso que este é um bom desafio, mas os resultados adicionais permitidos dificultam a obtenção de respostas. O PPCG procura critérios objetivos de vitória, e é difícil fazer isso quando existem tantas liberdades; isso não apenas altera o formato de saída, mas na verdade altera o que você pode produzir. Eu recomendaria editar as outras opções e apenas exigir a saída do número de placas perfeitas N.
HyperNeutrino 03/04

11
Pessoalmente, eu apreciaria muito mais esse desafio se fosse simplesmente validar se uma determinada placa é perfeita ou não (especialmente porque você não possui números definitivos para os casos de teste. Provavelmente tudo bem, desde que os resultados potenciais calculados são reduzidos Não tenho certeza sobre como outras pessoas se sentem embora Boa idéia embora..!
MildlyMilquetoast

4
Eu concordo com Mistah Figgins; Eu sinto que dessa forma, trata-se mais de encontrar um padrão, o que ainda é um desafio interessante, mas acho que isso pode atrair mais respostas se fosse apenas uma verificação de validação. Bom desafio!
HyperNeutrino

1
Publiquei um desafio estreitamente relacionado , esperando que ele chamasse a atenção para essa pergunta maravilhosa, além de simplificá-la um pouco, apenas procurando por placas (quase) perfeitas.
Sr. Xcoder 8/04

1
@carusocomputing Eu tentei o meu melhor, mas vim vazio. I foi enviado meu professor de matemática e ele está vazio até agora
Christopher

Respostas:


9

Python 3.6, 150 bytes

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

resultados:

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

Versão ungolfed com explicação:

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)

O problema se resume a procurar uma árvore na qual cada nível da árvore corresponde a uma posição no número de uma placa e cada nó tem 36 filhos (10 dígitos e 26 letras). A função faz uma pesquisa recursiva da árvore, acumulando os valores dos dígitos e letras à medida que avançam.

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.

Golf incluído, convertendo os loops for em somas de geradores:

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)

Em seguida, combinando os geradores. Codifique as letras A a Z como -1 a -26 e os dígitos como 0 a 9. Portanto, a soma se torna:

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

onde 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))

O restante do golfe está convertendo a função em um lambda, encurtando nomes de variáveis ​​e simplificando expressões.


Esta é uma solução eloquente, qual seria o tempo de execução? n*n*log(n)ou algo parecido?
Urna Mágica do Polvo

@carusocomputing Obrigado. A solução ainda gera todas as permutações possíveis do comprimento especificado, por isso tem a mesma complexidade que as outras soluções. Algo como k ** n, onde k é o número de símbolos no alfabeto (por exemplo, 10 dígitos + 26 letras = 36) e n é o número de símbolos em uma placa de carro. Executá-lo para n = 5 requer a verificação de 36 ^ 5 = 60.466.176 permutações e levou um minuto ou dois (a memorização pode acelerar, mas custaria muitos bytes ;-)).
RootTwo

6

Dyalog APL, 57 56 bytes

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

(assume ⎕io←0)

amatriz de todas as matrículas válidas (exceto 00...0) codificadas com: 0-9 para dígitos, 10-35 para letras

b máscara de bits para onde ocorrem os dígitos

c máscara de bits para o último dígito em todos os grupos de dígitos consecutivos



4

Python 2, 359 295 bytes

Bastante longo; Esta é a solução trivial. Estou confiante de que isso está correto, embora não corresponda aos casos de teste do desafio. As soluções que estou obtendo correspondem às respostas de Dada.

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 bytes graças a sugestões de @numbermaniac


1
Você pode salvar cerca de três bytes em c (x) e na última linha; remova um espaço entre 96 e for; entre map(ord,x)e if; e na última linha, entre .join(x)e for. Eu acho que você também pode economizar ainda mais se redefinir as funções para lambdas.
numbermaniac

@numbermaniac Thanks! (64 bytes total)
HyperNeutrino 04/04

4

Python 2 , 291 287 276 273 bytes

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

Experimente online!


Resultados:

0 0
1 0
2 18
3 355
4 8012

3

Perl 5 , 117 bytes

116 bytes de código + -psinalizador.

$"=",";@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$_}{

Experimente online!

Parece bastante abaixo do ideal, mas estou sem ideias no momento.
O código em si é muito ineficiente, pois calcula toda permutação de a..z,0..9comprimento n(leva aproximadamente 1 segundo por n=3, ~ 15 segundos n=4e ~ 7 minutos n=5).
O algoritmo é bastante direto: para cada placa de tamanho possível n(gerada com glob"{@F}"x$_- o globoperador é bastante mágico), $r*=eval s/./+$&/gr for/\d+/g;calcula o produto de cada parte dos dígitos e $r+=64-ord for/\pl/gsubtrai a ela o peso das letras. Em seguida, incrementamos o contador $\se $ris 0( !$r) e se a placa contém números e letras ( /\pl/*/\d/). $\é implicitamente impresso no final graças à -pbandeira.

Note que os números que eu obter são n=2 -> 18, n=3 -> 355, n=4 -> 8012, n=5 -> 218153. Tenho certeza de que esses são os corretos, mas posso estar enganado; nesse caso, avise-me e excluirei esta resposta.


3

APL (Dyalog) , 71 bytes

Corpo do programa completo. As solicitações de N. N≥4 requerem grandes quantidades de memória e computação.

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

Experimente online!


2

Scala, 265 bytes

(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(_*_))}

Explicações:

(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)
        )
}

Notas :

  • -64e -48são usados para transformar um Char(respectivamente letra e dígitos) ao seu Intvalor ( 'A' - 64 = 1, 'B' - 64 = 2..., '9' - 48 = 9)
  • O filtro in l.split("[A-Z]").filter(""<)é usado para eliminar ""valores se lcomeçar com uma letra (exemplo "A1".split("[A-Z]") => Array("", 1):). Pode haver uma solução melhor e mais curta

Casos de teste :

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

Resultados :

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

A função é bastante lenta n > 4porque todas as combinações devem ser geradas.


2

Java, 382 365 bytes

  • Economizou 17 bytes, graças a Kevin Cruijssen

Golfe

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);}

Detalhado

// 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); }

Eu acho que você precisa de uma função que apenas tome ncomo entrada.
Christian Sievers

@ChristianSievers corrigido
Khaled.K

1
Algumas coisas para se jogar no seu código atual: 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 bytes ) Você pode comparar sua versão atual com esta para ver as alterações que fiz (muito para caber no restante deste comentário). :)
Kevin Cruijssen

@KevinCruijssen thx, 17 bytes de desconto agora
Khaled.K

2

GAP , 416 bytes

Não vencerá no tamanho do código e está longe do tempo constante, mas usa a matemática para acelerar muito!

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;

Para espremer o espaço em branco desnecessário e obter uma linha com 416 bytes, passe por isso:

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

Meu antigo laptop "projetado para Windows XP" pode calcular f(10)em menos de um minuto e ir além em menos de uma hora:

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

Como funciona

Suponha que primeiro queremos saber apenas o número de placas perfeitas que se encaixam no padrão LDDLLDL, onde Lindica uma letra e Dindica um dígito. Suponha que temos uma lista lde números que l[i]fornece o número de maneiras pelas quais as letras podem fornecer o valor ie uma lista semelhante dpara os valores que obtemos dos dígitos. Então, o número de placas perfeitas com valor comum ié justo l[i]*d[i], e obtemos o número de todas as placas perfeitas com nosso padrão, somando isso em geral i. Vamos denotar a operação de obter essa soma por l@d.

Agora, mesmo que a melhor maneira de obter essas listas seja tentar todas as combinações e contar, podemos fazer isso de forma independente para as letras e os dígitos, observando 26^4+10^3casos em vez de 26^4*10^3 casos quando apenas percorremos todas as placas que se encaixam no padrão. Mas podemos fazer muito melhor: aqui lestá apenas a lista de coeficientes de (x+x^2+...+x^26)^konde kestá o número de letras 4.

Da mesma forma, obtemos o número de maneiras de obter uma soma de dígitos em uma sequência de kdígitos como coeficientes de (1+x+...+x^9)^k. Se houver mais de uma sequência de dígitos, precisamos combinar as listas correspondentes com uma operação d1#d2que na posição itenha como valor a soma de tudo em d1[i1]*d2[i2]que i1*i2=i. Essa é a convolução de Dirichlet, que é apenas o produto se interpretarmos as listas como coeficientes da série Dirchlet. Mas nós já os usamos como polinômios (séries finitas de potência) e não há uma boa maneira de interpretar a operação para eles. Eu acho que essa incompatibilidade faz parte do que torna difícil encontrar uma fórmula simples. Vamos usá-lo em polinômios de qualquer maneira e usar a mesma notação #. É fácil calcular quando um operando é um monômio: temosp(x) # x^k = p(x^k). Juntamente com o fato de ser bilinear, isso fornece uma maneira agradável (mas não muito eficiente) de computá-lo.

Observe que as kletras dão um valor de no máximo 26k, enquanto k os dígitos únicos podem dar um valor de 9^k. Portanto, frequentemente obteremos altas potências desnecessárias no dpolinômio. Para se livrar deles, podemos calcular o módulo x^(maxlettervalue+1). Isso dá uma grande velocidade e, embora eu não tenha notado imediatamente, até ajuda no golfe, porque agora sabemos que o grau de dnão é maior que o de l, o que simplifica o limite superior na final Sum. Nós obtemos uma velocidade ainda melhor ao fazer um modcálculo no primeiro argumento de Value (ver comentários), e fazer todo o #cálculo em um nível mais baixo fornece uma velocidade incrível. Mas ainda estamos tentando ser uma resposta legítima para um problema no golfe.

Portanto, temos o nosso le dpodemos usá-lo para calcular o número de placas perfeitas com padrão LDDLLDL. Esse é o mesmo número do padrão LDLLDDL. Em geral, podemos alterar a ordem das séries de dígitos de diferentes comprimentos, conforme desejamos, NrArrangementsfornece o número de possibilidades. E enquanto deve haver uma letra entre as execuções de dígitos, as outras letras não são fixas. O Binomialconta essas possibilidades.

Agora, resta analisar todas as formas possíveis de ter comprimentos de dígitos de execuções. ratravessa todos os números de pistas, catravés de todos os números totais de dígitos, e patravés de todas as partições de ccom rsummands.

O número total de partições que observamos é dois a menos do que o número de partições n+1, e as funções da partição aumentam como exp(sqrt(n)). Portanto, embora ainda haja maneiras fáceis de melhorar o tempo de execução reutilizando resultados (executando as partições em uma ordem diferente), para uma melhoria fundamental, precisamos evitar olhar cada partição separadamente.

Computando rápido

Note isso (p+q)@r = p@r + q@r. Por si só, isso apenas ajuda a evitar algumas multiplicações. Mas junto com (p+q)#r = p#r + q#risso significa que podemos combinar por polinômios de adição simples correspondentes a diferentes partições. Não podemos simplesmente adicioná-los todos, porque ainda precisamos saber com os quais ldevemos @combinar, qual fator devemos usar e quais #extensões ainda são possíveis.

Vamos combinar todos os polinômios correspondentes às partições com a mesma soma e comprimento, e já consideramos as várias maneiras de distribuir os comprimentos das execuções de dígitos. Diferente do que especulei nos comentários, não preciso me preocupar com o menor valor usado ou com que frequência ele é usado, se tiver certeza de que não estenderei esse valor.

Aqui está o meu código 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" ;
}

Isso usa a biblioteca GNU MP. No debian, instale libgmp-dev. Compile com g++ -std=c++11 -O3 -o pl pl.cpp -lgmp -lgmpxx. O programa leva seu argumento de stdin. Para cronometrar, use echo 100 | time ./pl.

No final, a[sum][length][i]fornece o número de maneiras pelas quais os sum dígitos nas lengthexecuções podem fornecer o número i. Durante a computação, no início do mloop, fornece o número de maneiras que podem ser feitas com números maiores que m. Tudo começa com a[0][0][1]=1. Observe que este é um superconjunto dos números que precisamos para calcular a função para valores menores. Assim, quase ao mesmo tempo, poderíamos calcular todos os valores até n.

Como não há recursão, temos um número fixo de loops aninhados. (O nível de aninhamento mais profundo é 6.) Cada loop passa por vários valores lineares no npior dos casos. Então, precisamos apenas de tempo polinomial. Se observarmos mais de perto o aninhado ie o jloop extend, encontraremos um limite superior para jo formulário N/i. Isso deve fornecer apenas um fator logarítmico para o jloop. O loop mais interno f (com sumnetc) é semelhante. Lembre-se também de que computamos com números que crescem rapidamente.

Observe também que armazenamos O(n^3)esses números.

Experimentalmente, obtenho esses resultados em hardware razoável (i5-4590S): f(50)precisa de um segundo e 23 MB, f(100)precisa de 21 segundos e 166 MB, f(200)precisa de 10 minutos e 1,5 GB e f(300)precisa de uma hora e 5,6 GB. Isso sugere uma complexidade de tempo melhor que O(n^5).


Como este é um desafio de código de golfe, esta resposta precisa ser jogada no golfe . Desculpe.
Rɪᴋᴇʀ

1
@Riker Embora eu não ache que meu código seja muito detalhado, eu joguei um pouco mais e assumi o ônus de determinar seu tamanho quando o espaço em branco é espremido.
Christian Sievers

1
@carusocomputing Acho que é muito pior. Estou lidando separadamente com cada caso de distribuição de dígitos entre execuções de dígitos, como uma execução de três dígitos, ou uma execução de dois dígitos e um dígito único, ou há três dígitos únicos, mas n=5, para , não há maiúsculas e minúsculas com uma sequência de dois dígitos e dois dígitos únicos, porque não temos letras suficientes para separar os números. É isso que os três forloops externos fazem: percorrem todas as partições úteis de números <n. (E acabei de perceber que também permito ndígitos. Por pura sorte, outra otimização conta isso como 0).
Christian Sievers

1
@carusocomputing Observe que, para números <n/2, todas as partições são úteis. E os cálculos restantes ainda levam um tempo não constante. Para ver o que está acontecendo, você pode adicionar Print(p,"\n");no início do corpo do for p...loop. - Tive uma idéia para usar um loop a menos, mas isso ajudará apenas no tamanho do código.
Christian Sievers

2
Eu recebo uma velocidade incrível movendo o mod(que já ajudou bastante) Value, mudando para Value(d mod x^(1+QuoInt(s(l)-1,i-1)),x^(i-1)). Só isso permite calcular f(15)em 80 segundos.
Christian Sievers

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.