尤拉計劃698:123數

lt發表於2020-01-19

我們定義123數如下:
- 1是最小的123數。
- 以10進製表示時,只顯示數字“ 1”,“ 2”和“ 3”,而且它們出現的次數也是123數。

所以,2是一個123數,因為它由1個數字“ 2”組成,而1是一個123數。所以,33也為123數,因為它由2個數字“ 3”組成,而2也為123數。
但是,1111不是123數,因為它包含4個數字“ 1”,而4不是123數。

按照升序排列,前面的123數分別為:
1,2,3,11,12,13,21,22,23,31,32,33,111,112,113,121,122,123,131,...

令F(n)是第n個123數。例如
F(4)= 11
F(10)= 31
F(40)= 1112
F(1000)= 1223321
F(6000)= 2333333333323

求F(111111111111222333)
把您的答案取模123123123

一個簡單的測試程式

a=[1,2,3]

def j(n):
 if n in a or n==0: return 1  
 c=[0,0,0,0]
 for i in str(n):
  if i not in '123':
   return 0
  else: 
   c[int(i)]+=1
 else: return j(c[1])*j(c[2])*j(c[3])

x=[i for i in range(0,2*10**6) if j(i)==1]
for i in range(1,len(x)):
 if i in (4,10,40,1000,6000):print(x[i])

11
31
1112
1223321

一個更快的生成器,可以驗證F(6000),但是更多位數就記憶體錯誤了

n=[]

def prt(x):
 lenx=0 
 cnt=0
 for i in range(1,len(x)):
  cnt+=1
  if len(str(x[i]))>lenx:lenx=len(str(x[i]));print(lenx,x[i],cnt);cnt=0

def gen(rr): 
 sm=[0,1,2,3,11,12,13] 
 e=['1','2','3']
 w=[[0,1,0,0],[0,0,1,0],[0,0,0,1]] 
 t=e
 tw=list(w)
 for r in range(0,rr): #x,xx,xxx,xxxx
  for i in range(0,len(t)):
   if (tw[i][1] in sm) and (tw[i][2] in sm) and (tw[i][3] in sm):
     n.append(t[i])
  t=[i+j for i in e for j in t]  
  tw=[[0,i[1]+j[1],i[2]+j[2],i[3]+j[3]]for i in w for j in tw] 

gen(10)
prt(n)
>>> gen(13)
>>> prt(n)
(1, '2', 1)
(2, '11', 2)
(3, '111', 9)
(4, '1112', 27)
(5, '11122', 78)
(6, '111222', 210)
(7, '1112223', 510)
(8, '11122233', 1050)
(9, '111222333', 1680)
(11, '11111111111', 1680)
(12, '111111111111', 3)
(13, '1111111111111', 75)
(14, '11111111111112', 1017)
>>> n[5999]
'2333333333323'

快速計算長度為n的123數個數

def cnt(n):
 sm=[0,1,2,3,11,12,13]
 x=[[n1,n2,n3]for n1 in sm for n2 in sm for n3 in sm if n1+n2+n3==n]
 #print(x)
 c=0
 for i in x:
  n1,n2=i[0],i[1]
  c+=comb(n1,n)*comb(n2,n-n1)
 return c 

def comb(t,n):
 p=1
 for i in range(t):
  p*=(n-i)
 for i in range(t):
  p//=(i+1)
 return p

for i in range(1,30):print(i,cnt(i))
...
1 3
2 9
3 27
4 78
5 210
6 510
7 1050
8 1680
9 1680
10 0
11 3
12 75
13 1017
14 9912
15 69510
16 351960
17 1213800
18 1627920
19 1627920
20 0
21 0
22 2116296
23 56787276
24 801886260
25 7909656300
26 29438898300
27 79330576500
28 114011377200
29 114011377200  

最終正確的程式碼,能算到100位,更多時,要增加sm(小的123數列表)的個數

def cnt(n):
 sm=[0,1,2,3,11,12,13, 21, 22, 23, 31, 32, 33]
 x=[[n1,n2,n3]for n1 in sm for n2 in sm for n3 in sm if n1+n2+n3==n]
 return cnt2(x,n)


def cnt2(x,n):
 c=0
 for i in x:
  n1,n2=i[0],i[1]
  c+=comb(n1,n)*comb(n2,n-n1)
 return c


def comb(t,n):
 p=1
 for i in range(t):
  p*=(n-i)
 for i in range(t):
  p//=(i+1)
 return p


def sech(s,v,t,n):
 if begin+v==y: return
 b=[[1,0,0],[0,1,0],[0,0,1]]
 for p in range(3):
  tmp=[[i[0]-b[p][0],i[1]-b[p][1],i[2]-b[p][2]] for i in t if i[p]-1>=0]
  ct=cnt2(tmp,n-1)
  if begin+v+ct>=y: s+=str(1+p);print(s,v);sech(s,v,tmp,n-1);break
  else :v+=ct


s=0
c=0
#y=6000
y=111111111111222333
j=0
for i in range(1,50):
 c=cnt(i)
 s+=c
 if s>=y:
  j=i
  print(i,c,s)
  break


sm=[0,1,2,3,11,12,13, 21, 22, 23, 31, 32, 33]
x=[[n1,n2,n3]for n1 in sm for n2 in sm for n3 in sm if n1+n2+n3==j]


begin=s-c
st='{'
ct=0

v=0;sech(st,v,x,j)

相關文章