[Esta pergunta é um acompanhamento para calcular as execuções de uma string ]
Um período
p
de uma stringw
é qualquer número inteiro positivo, dep
modo que,w[i]=w[i+p]
sempre que ambos os lados desta equação forem definidos. Vamosper(w)
denotar o tamanho do menor período dew
. Dizemos que uma stringw
é periódica seper(w) <= |w|/2
.
Tão informalmente, uma sequência periódica é apenas uma sequência composta de outra sequência repetida pelo menos uma vez. A única complicação é que, no final da sequência, não exigimos uma cópia completa da sequência repetida, desde que seja repetida na íntegra pelo menos uma vez.
Por exemplo, considere a sequência x = abcab
. per(abcab) = 3
como x[1] = x[1+3] = a
, x[2]=x[2+3] = b
e não há período menor. A sequência abcab
não é, portanto, periódica. No entanto, a cadeia ababa
é periódica como per(ababa) = 2
.
Como outros exemplos, abcabca
, ababababa
e abcabcabc
também são periódicas.
Para quem gosta de expressões regulares, este detecta se uma sequência é periódica ou não:
\b(\w*)(\w+\1)\2+\b
A tarefa é encontrar todas as substrings periódicas máximas em uma sequência mais longa. Essas são algumas vezes chamadas de execuções na literatura.
Uma substring
w
é uma substring periódica máxima (execução) se for periódica e não forw[i-1] = w[i-1+p]
nemw[j+1] = w[j+1-p]
. Informalmente, a "execução" não pode estar contida em uma "execução" maior com o mesmo período.
Como duas execuções podem representar a mesma sequência de caracteres que ocorre em locais diferentes na sequência geral, representaremos as execuções por intervalos. Aqui está a definição acima repetida em termos de intervalos.
Uma execução (ou substring periódica máxima) em uma string
T
é um intervalo[i...j]
comj>=i
, de modo que
T[i...j]
é uma palavra periódica com o períodop = per(T[i...j])
- É o máximo. Formalmente, nem
T[i-1] = T[i-1+p]
nemT[j+1] = T[j+1-p]
. Informalmente, a execução não pode estar contida em uma execução maior com o mesmo período.
Indique pelo RUNS(T)
conjunto de execuções na cadeia de caracteres T
.
Exemplos de execuções
Os quatro substrings periódicas máximas (runs) em corda
T = atattatt
sãoT[4,5] = tt
,T[7,8] = tt
,T[1,4] = atat
,T[2,8] = tattatt
.A cadeia de caracteres
T = aabaabaaaacaacac
contém os seguintes máximos 7 subsequências periódicos (separações):T[1,2] = aa
,T[4,5] = aa
,T[7,10] = aaaa
,T[12,13] = aa
,T[13,16] = acac
,T[1,8] = aabaabaa
,T[9,15] = aacaaca
.A sequência
T = atatbatatb
contém as três execuções a seguir. Eles são:T[1, 4] = atat
,T[6, 9] = atat
eT[1, 10] = atatbatatb
.
Aqui estou usando a indexação 1.
A tarefa
Escreva o código para que, para cada número inteiro n começando em 2, você produza o maior número de execuções contidas em qualquer cadeia de comprimento binária n
.
Ponto
Sua pontuação é a mais alta que n
você alcança em 120 segundos, de modo que, para todos k <= n
, ninguém postou uma resposta correta mais alta que você. Claramente, se você tiver todas as respostas ideais, obterá a pontuação mais alta n
que postar. No entanto, mesmo que sua resposta não seja a ideal, você ainda pode obter a pontuação se ninguém mais conseguir vencê-la.
Línguas e bibliotecas
Você pode usar qualquer idioma e bibliotecas disponíveis que desejar. Onde for possível, seria bom poder executar seu código; portanto, inclua uma explicação completa de como executar / compilar seu código no Linux, se possível.
Exemplo optima
No seguinte: n, optimum number of runs, example string
.
2 1 00
3 1 000
4 2 0011
5 2 00011
6 3 001001
7 4 0010011
8 5 00110011
9 5 000110011
10 6 0010011001
11 7 00100110011
12 8 001001100100
13 8 0001001100100
14 10 00100110010011
15 10 000100110010011
16 11 0010011001001100
17 12 00100101101001011
18 13 001001100100110011
19 14 0010011001001100100
20 15 00101001011010010100
21 15 000101001011010010100
22 16 0010010100101101001011
O que exatamente meu código deve produzir?
Para cada um, n
seu código deve gerar uma única string e o número de execuções que ele contém.
Minha máquina Os horários serão executados na minha máquina. Esta é uma instalação padrão do ubuntu em um processador AMD FX-8350 de oito núcleos. Isso também significa que eu preciso poder executar seu código.
Respostas principais
- 49 por Anders Kaseorg em C . Thread único e executado com L = 12 (2 GB de RAM).
- 27 por cdlane em C .
fonte
{0,1}
-strings, indique explicitamente isso. Caso contrário, o alfabeto pode ser infinito, e não vejo por que seus casos de teste devem ser ótimos, porque parece que você{0,1}
também pesquisou as strings também.n
até12
e nunca bater o alfabeto binário. Heuristicamente, eu esperaria que uma string binária fosse ótima, porque adicionar mais caracteres aumenta o comprimento mínimo de uma execução.Respostas:
C
Isso faz uma pesquisa recursiva por soluções ótimas, altamente otimizadas usando um limite superior no número de execuções que podem ser concluídas pelo restante desconhecido da sequência. O cálculo do limite superior usa uma tabela de pesquisa gigantesca cujo tamanho é controlado pela constante
L
(L=11
: 0,5 GiBL=12
,: 2 GiBL=13
,: 8 GiB).No meu laptop, isso aumenta n = 50 em 100 segundos; a próxima linha chega aos 142 segundos.
Saída:
Aqui estão todas as seqüências ideais para n ≤ 64 (não apenas o primeiro lexicograficamente), geradas por uma versão modificada deste programa e por muitas horas de computação.
Uma sequência quase ótima
Os prefixos da sequência fractal infinita
que é invariável sob a transformação 101 × 10100, 00 × 101:
parecem ter números quase ótimos de execuções - sempre dentro de 2 da ideal para n ≤ 64. O número de execuções nos primeiros n caracteres divididos por n abordagens (13 - 5√5) / 2 ≈ 0,90983. Mas acontece que essa não é a proporção ideal - veja os comentários.
fonte
Como não é uma corrida se houver apenas um cavalo, estou enviando minha solução, embora seja apenas uma fração da velocidade de Anders Kaseorg e uma apenas um terço como enigmática. Ajuntar com:
O coração do meu algoritmo é uma mudança simples e um esquema XOR:
Uma execução de zeros no resultado XOR que é maior ou igual ao período / turno atual indica uma execução na sequência original para esse período. A partir disso, você pode dizer quanto tempo durou a execução e onde começa e termina. O restante do código está sobrecarregado, configurando a situação e decodificando os resultados.
Espero que faça pelo menos 28 depois de dois minutos na máquina de Lembik. (Eu escrevi uma versão pthread, mas só consegui fazê-la funcionar ainda mais devagar.)
Saída:
fonte
-O3
não pretende ser "inseguro". Permite a auto-vetorização, mas provavelmente não há nada para vetorizar aqui. Às vezes, pode tornar o código mais lento, por exemplo, se ele usa um cmov sem ramificação para algo em que uma ramificação teria previsto muito bem. Mas geralmente deve ajudar. Também vale a pena tentar clang também, para ver qual gcc ou clang cria um código melhor para um loop específico. Além disso, quase sempre ajuda a usar-march=native
, ou pelo menos-mtune=native
se você ainda deseja um binário que roda em qualquer lugar.