Número de multisets de modo que cada número de 1 a

11

Meu problema. Dada n , quero contar o número de válido multisets S . Um multiset S é válido se

  • A soma dos elementos de S é n , e
  • Cada número de 1 a n pode ser expressa de forma única como uma soma de alguns dos elementos de S .

Exemplo. Por exemplo, se n=5 , {1,1,1,1,1},{1,2,2},{1,1,3} são válidos.

No entanto, S={1,1,1,2} é inválido porque 2 pode ser formado por {1,1} e {2} (ou seja, 2 pode ser expresso como 2=1+1 e 2=2 ) , portanto, a segunda condição não é válida. Da mesma forma 3 pode ser formado por {2,1} e {1,1,1} .

S={1,2,4 } também é inválido porque todos os números de1 a5 podem ser feitos exclusivamente, mas a soma dos elementos deS não é5 .


Eu tentei encontrar um bom algoritmo para esse problema por algum tempo, mas não consigo resolvê-lo. É de codechef . Eu já vi algumas das soluções enviadas, mas ainda não consegui obter a lógica para resolver o problema. NOTA: O limite de tempo para a pergunta é de 10 segundos e n<109

Para um multiset, usarei a notação S={(a1,c1),(a2,c2)...} ai<aj se i<j , o que significa ai ocorre ci vezes na multiconjunto S.

Até agora eu tirei algumas conclusões

  • O primeiro elemento do multiset classificado necessário deve ser 1
  • Seja é um conjunto seguindo as duas propriedades, então r < k a r + 1 = a r  ou  ( r i = 0 a i ) + 1S={1,a2ak}|a1a2akr<k  ar+1=ar or (i=0rai)+1
  • Seja , onde a i ocorre c i vezes, segue as propriedades necessárias e, a partir da conclusão acima, podemos dizer que i a i | n + 1 eS={(1,c1),(a2,c2)(ak,ck)}|a1a2akaicii ai|n+1 se j > i . Prova: a i + 1 = ( a i c i + a i - 1 ) + 1 a i | a i + 1ai|ajj>i
    ai+1=(aici+ai1)+1ai|ai+1
  • Agora, considere ou seja, todo o os números subseqüentes após 1 serão múltiplos de d . Então vamos f ( n )S={1,11d1,d,dd,dm1,dm1dm1,dm2,dm2dm2,}df(n)seja possível a contagem desse multiset, então onde estou somando todo o número possível de1's(=d-1). Em outros termosf(n-1)=g(n)=d| n,dng(d)f(n)=d|n+1,d1f(n(d1)d)1s=d1f(n1)=g(n)=d|n,dng(d)

Finalmente, meu problema é reduzido a isso - encontre maneira eficiente para que não exceda o limite de tempo.g(n)

Liga da Justiça
fonte
2
Você verificou se é apropriado solicitar que outras pessoas publiquem publicamente soluções e algoritmos para problemas práticos? O FAQ do Codechef parece esperar que as soluções não sejam publicadas publicamente (exceto por alguns problemas muito básicos). A publicação de uma solução aqui estaria "estragando" os problemas da prática para os outros, ou isso é considerado bom? Não estou familiarizado com as normas e a etiqueta da comunidade de Codechef.
DW
Não encontrei nada relacionado a não postar perguntas no domínio público nas perguntas frequentes e essa restrição está nos problemas contínuos do concurso e não no problema da prática.
liga da justiça
1
@DW Eu não acho que eles se importariam se discutíssemos prblems que não são de concursos em andamento.
Ravi Upadhyay
1
Você está procurando o número de partições do número de entrada. Eu sugiro que você faça alguma pesquisa usando esse chavão.
Raphael
2
@ Rafael, eu concordo, o pôster deve ler sobre essas técnicas. Não é exatamente o mesmo problema - a primeira condição do pôster exige que seja uma partição, mas a segunda condição impõe restrições adicionais (para alterações exclusivas ) - mas pode ser possível aplicar as mesmas técnicas usadas para contar o número de partições, com algumas modificações para lidar com o requisito adicional.
DW

Respostas:

2

Aqui está o que a solução mais rápida está fazendo. Na verdade, está computando sua função Dado n , nós o fatoramos (veja abaixo) e depois calculamos todos os fatores (veja abaixo) f 1 , , f m em alguma ordem tal que f i | f j implica i j (propriedade P). Agora calculamos g de acordo com a fórmula, revisando os fatores na ordem dada. A propriedade P garante que, quando calculamos g ( d ) , já calculamos g ( e ) para todos os fatores não triviais e

g(n)=dnd<ng(d),g(1)=1.
nf1,,fmfi|fjijgg(d)g(e)ede . Há também uma otimização (veja abaixo).d

Mais detalhadamente, examinamos os fatores em ordem e, para cada fator , encontramos todos os seus fatores não triviais, verificando qual de f 1 , ... , f i - 1 divide f i .fif1,,fi1fi

Factoring: Pré - processamento: fazemos uma lista de todos os números primos abaixo de usando a peneira de Eratóstenes. Dado n , simplesmente usamos a divisão de teste.109n

Gerando todos os fatores: isso é feito recursivamente. Suponha que . Executamos t loops aninhados l 1{ 0 , , k 1 } , , l t{ 0 , , k t } e produzimos p l 1 1p l t t . Você pode provar a propriedade P por indução.n=p1k1ptkttl1{0,,k1},,lt{0,,kt}p1l1ptlt

Otimização: Como o programa é executado em várias entradas, podemos usar a memorização para economizar tempo em diferentes entradas. Memorizamos apenas valores pequenos (até ), e isso nos permite armazenar todos os valores memorizados em uma matriz. A matriz é inicializada com zeros e, portanto, podemos dizer quais valores já são conhecidos (já que todos os valores calculados são positivos).105


Se a fatoração primária de for p k 1 1 , , p k t t , então f ( n ) depende apenas de ( k 1 , , k t ) e, de fato, apenas da versão classificada desse vetor . Todo número abaixo de 10 9 tem no máximo 29 fatores primos (com repetição) e, como p ( 29 ) = 4565 , parece possível calcular fn+1p1k1,,ptktf(n)(k1,,kt)10929p(29)=4565f(ou melhor, ) para todos eles, recursivamente. Essa solução poderia ser mais rápida se houvesse muitas entradas diferentes; como é, existem no máximo 10 .g10

Também é possível que essa função, mapeando partições para o correspondente , tenha uma forma analítica explícita. Por exemplo, g ( p k ) = 2 k - 1 , g ( p 1p t ) é dado por A000670 e g ( p 2 1 p 2p t ) é dado por A005649 ou A172109 .gg(pk)=2k1g(p1pt)g(p12p2pt)

Yuval Filmus
fonte
1

OK, então você tem uma relação de recorrência para (consulte o final de sua pergunta).g()

Nesse ponto, parece que uma abordagem natural seria escrever o algoritmo recursivo para calcular e aplicar a memorização para não computar g ( i ) mais de uma vez. Em outras palavras, quando você calcula g ( i ) , armazena-o em uma tabela de hash que mapeia i g ( i ) ; se precisar conhecer g ( i ) novamente no futuro, procure-o na tabela de hash.g(n)g(i)g(i)ig(i)g(i)

nnn109

g(1),g(2),g(3),g(4),g(5),

DW
fonte
0

Aqui está uma dica para você começar. Aplique algoritmos de programação dinâmica padrão para enumerar o conjunto de partições de um número inteiro e adicione alguma lógica para verificar qual delas permite a realização de alterações exclusivas, verificando iterativamente todas as somas, fazendo alterações e verificando a exclusividade.

Si1inSi

SnS

P(n)P(1),P(2),,P(n)P(n+1)


Aqui está uma abordagem que provavelmente será melhor.

SnTSTn

xSSTxSSTn

SA[1|S|,1n]A[i,j]jiSiSSS={s1,s2,,sk}s1s2skA[i,j]A[1i1,1j1]A[i,j]=A[i1,j]A[i1,jsi]j>siA[i,j]=A[i1,j]S

TSSTnSnTn+1,n+2,,nTAA[1|T|,1n]A[|T|,n+1],A[|T|,n+2],,A[|T|,n]TS

Snn20P[120]P[5]SP[n]Sn

P[n]P[1]{1}nSP[n]TSnTTP[n]n20

Isso deve ser bem factível. Boa sorte! Diverta-se! Trabalhar com os detalhes será um bom exercício de aprendizado em programação dinâmica.

DW
fonte
n