尤拉計劃696:麻將
字數太多,上圖
麻將的遊戲是玩s種花色的牌.每張牌也有一個在範圍1..n內的數字,對於每個花色/數字組合,正好有四張相同花色和數字的牌。(真正的麻將遊戲也包含其他獎賞牌,但這些在此問題中不考慮。)
糊牌的一手是3t+2張牌(其中t是固定整數),它可以安排為t個 三重和一對,其中:
- 三重是順子或碰
- 順子是三張相同花色和連續數字的牌
- 碰是三張相同的牌(相同花色和相同數字)
- 對是兩張相同的牌(相同花色和相同數字)
例如,下面是一隻勝利的手,它包括兩個順子,兩個碰和一對:
請注意,有時相同的切片集合可以以多種方式表示為三重和一對。這隻能算作一隻糊牌的手。例如,下面被認為是與上面相同的糊牌手,因為它們由相同的牌組成:
設 w(n,s,t)是t個三重和一對形成不同的糊牌手的數量,其中牌的花色數為s,數字最大為n。
例如,對於單個花色和牌數字最大為 4,我們有w(4,1,1)=20 :其中有12只糊牌的手,包括一個碰和一對,另外8個糊牌的手,包括一隻順子和一對。已知
w(9,1,4)=13259 w(9,3,4)=5237550 w(1000,1000,5)≡107662178(mod 1000000007)
求:w(10^8 ,10^8 ,30)給出mod 1000000007的答案.
用sql模擬w(4,1,1)
with p as
(select level||','||level||',' n, power(10,level)*2 flg from dual connect by level<=9)
,c as
(select level||','||level||','||level||',' n , power(10,level)*3 flg from dual connect by level<=9
union
select level||','||(level+1)||','||(level+2)||',' n, power(10,level)*111 flg from dual connect by level<=9-2)
,t(lv,s,flg) as(
select 0,n s,flg from p
union all
select lv+1,s||n,t.flg+c.flg from t,c where lv<4 and regexp_instr(t.flg+c.flg,'[5-9]')=0)
select count(*),count(distinct flg) from t where lv=4 ;
COUNT(*) COUNT(DISTINCTFLG)
-------- ------------------
300366 13259
用相同思路實現的python遞迴程式如下:
import re
def pai(n):
c=[[i,i] for i in range(1,n+1)]
return c
def peng(n):
c=[[i,i,i] for i in range(1,n+1)]
return c
def chow(n):
c=[[i,i+1,i+2] for i in range(1,n-1)]
return c
x=chow(9)+peng(9)
x.sort()
lenx=len(x)
xflg=[0]*lenx
for i in range(0,lenx):
for j in x[i]:
xflg[i]+=10**j
print(xflg)
cnt=0
def mj(lv,flg,last_i):
global cnt
global set_a
if last_i==lenx: return -1
if lv==4 : cnt+=1;set_a.add(flg);return 0
for i in range(last_i,lenx):
newflg= xflg[i]+flg
m=re.search('[5-9]',str(newflg))
if m==None: #each number occurs less than 5 times
mj(lv+1,newflg,i)
set_a=set()
cnt=0
for i in pai(9):
mj(0,(10**i[0])*2,0)
print(cnt)
print(len(set_a))
def wt():
fileObject = open('sampleList.txt', 'w')
for ip in set_a:
fileObject.write(str(ip))
fileObject.write('\n')
fileObject.close()
輸出結果
>>> print(cnt)
14738
>>> print(len(set_a))
13259
修改上述程式碼中的引數,得到w(9,3,4)
x=chow(29)+peng(29)
x=[i for i in x if 10 not in i and 20 not in i]
x.sort()
set_a=set()
cnt=0
pa=[i for i in pai(29) if 10 not in i and 20 not in i]
for i in pa:
mj(0,(10**i[0])*2,0)
>>>> print(cnt)
5296275
>>>> print(len(set_a))
5237550
重寫了mj2函式和計算總數的w函式
def mj2(lv,flg,last_i,s,t):
global cnt,lenx
#print(lenx)
if last_i==lenx: return -1
if lv==t : cnt+=1;set_a.add(flg);return 0
for i in range(last_i,lenx):
newflg= xflg[i]+flg
m=re.search('[5-9]',str(newflg))
if m==None:
mj2(lv+1,newflg,i,s,t)
def w(n,s,t):
global x,xflg,pa,lenx,cnt
x=[]
for i in chow((n+1)*s-1)+peng((n+1)*s-1):
for j in range(1,s+1):
if (n+1)*j in i:break
else: x.append(i)
x.sort()
lenx=len(x)
xflg=[0]*lenx
for i in range(0,lenx):
for j in x[i]:
xflg[i]+=10**j
cnt=0
pa=[]
for i in pai((n+1)*s-1):
for j in range(1,s+1):
if (n+1)*j in i:break
else: pa.append(i)
for i in pa:
mj2(0,(10**i[0])*2,0,s,t)
return len(set_a)
for i in range(0,5):set_a=set();x=[];xflag=[];pa=[];lenx=0;cnt=0;print(i+4,w(4+i,1,1))
4 20
5 35
6 54
7 77
8 104
for i in range(0,5):set_a=set();x=[];xflag=[];pa=[];lenx=0;cnt=0;print(i+4,w(4+i,4,1))
4 368
5 620
6 936
7 1316
8 1760
總結出w(n,s,1)=ns(2ns-2s-1)
測試w(n,s,2),計算差分,應該是3次方程,用4組值,mathematica解方程組得出w(n,s,2)=s(2s^2n^3-2s(2s+1)n^2+(s+1)(2s-1)n+6)
for i in range(0,20):set_a=set();x=[];xflag=[];pa=[];lenx=0;cnt=0;print(i+4,w(4+i,5,2))
4 8310
5 18880
6 35850
7 60720
8 94990
In[17]:= Solve[
a*4^3+b*4^2+c*4+d==8310 &&
a*5^3+b*5^2+c*5+d==18880 &&
a*6^3+b*6^2+c*6+d==35850 &&
a*7^3+b*7^2+c*7+d==60720,
{a,b,c,d}]
Out[17]= {{a -> 250, b -> -550, c -> 270, d -> 30}
t=3的公式
In[115]:= Factor[w53[x]]
2 3 4
5 (-192 - 6 x + 1525 x - 1650 x + 500 x )
Out[115]= -------------------------------------------
3
In[104]:= Factor[w43[x]]
2 3 4
4 (-156 + 141 x + 764 x - 864 x + 256 x )
Out[104]= -------------------------------------------
3
In[93]:= Factor[w33[x]]
2 3 4
Out[93]= 3 (-40 + 64 x + 101 x - 126 x + 36 x )
In[94]:= Factor[w23[x]]
2 3 4
2 (-84 + 171 x + 70 x - 120 x + 32 x )
Out[94]= ----------------------------------------
3
In[95]:= Factor[w13[x]]
2 3 4
-48 + 102 x - 7 x - 18 x + 4 x
Out[95]= ---------------------------------
3
容易觀察到x^4的係數是4 s^3, 常數項的係數是-36 s -12,所以只要求x、x^2、x^3的係數,設x^3的係數是
a s^3+b s^2 +c s +d
, 利用上述公式的s=1~4項聯立方程組:
Solve[
a 1^3+b 1^2 +c 1 +d ==-18 &&
a 2^3+b 2^2 +c 2 +d ==-120 &&
a 3^3+b 3^2 +c 3 +d ==-126*3 &&
a 4^3+b 4^2 +c 4 +d ==-864 ,
{a,b,c,d}]
解得{{a -> -12, b -> -6, c -> 0, d -> 0}}
,所以係數是-12 s^2 -6 s
,用s=5代入值為-1650,與w53的表示式比較,結果正確。同樣方法求得x^2的係數12 s^3 +6 s^2 -25 s
,x的係數-4 s^3 +97 s +9
,所以得到wns3的通項公式為wns3[n_,s_]:=(-36 s -12 +(-4 s^3 +97 s +9)n +(12 s^3 +6 s^2 -25 s)n^2+ (-12 s^3-6 s^2 )n^3+ 4 s^3 n^4)s /3
當t=4時,和t=3的情況類似,前幾個數值無法用公式描述,要從w(9,1,4)開始符合公式
wn14[n_]:=2/3 n^5-4 n^4-26/3 n^3+96 n^2-140 n-61
利用相同辦法,求得:
wn24[n_]:=64/3 n^5-320/3 n^4+128/3 n^3+1712/3 n^2-822 n-46
在膝上型電腦上執行程式算w(10,3,4)時,產生記憶體不足錯誤。考慮到列表的儲存空間是集合的1/4(參考https://www.ituring.com.cn/article/509014),並且重複數佔總數的比例很低,而計算不重複數只需要最後一步算,因此改寫mj2函式為 而在w函式最後加上排序和不重複計數程式碼。
def mj4(lv,flg,last_i,s,t):
global cnt,lenx
#print(lenx)
if last_i==lenx: return -1
if lv==t :
cnt+=1
sortlst_a.append(flg)
return 0
for i in range(last_i,lenx):
newflg= xflg[i]+flg
m=re.search('[5-9]',str(newflg))
if m==None:
mj4(lv+1,newflg,i,s,t)
def w3(n,s,t):
global x,xflg,pa,lenx,cnt
x=[]
for i in chow((n+1)*s-1)+peng((n+1)*s-1):
for j in range(1,s+1):
if (n+1)*j in i:break
else: x.append(i)
x.sort()
lenx=len(x)
xflg=[0]*lenx
for i in range(0,lenx):
for j in x[i]:
xflg[i]+=10**j
cnt=0
pa=[]
for i in pai((n+1)*s-1):
for j in range(1,s+1):
if (n+1)*j in i:break
else: pa.append(i)
for i in pa:
mj4(0,(10**i[0])*2,0,s,t)
slen= len(sortlst_a)
sortlst_a.sort()
ucnt=0
oldv=0
for i in range(0,slen):
if sortlst_a[i] !=oldv: ucnt+=1;oldv=sortlst_a[i]
return ucnt
這樣改造後,利用程式最多可以算到w(12,3,4),離計算5次多項式方程組所需的等式還差2個。
好在根據wnst在t=1,2時的結果,通項公式的最高次係數有規律,2/3,64/3,總結為2*s^t/3,所以最高項次數為2*3^5/3=162(實際上n、s的次數應該相同)。這樣減少一個未知數,只需要額外的1個等式。
再次根據上述經驗,wn34的實際值在n=9前比公式值略小,小的這個值一定是3的倍數,所以嘗試在w(8,3,4)的實際值上加3,作為額外的等式,得到如下方程組:
In[15]:= Solve[
162*8 ^5+x*8 ^4+a*8 ^3+b*8 ^2+c*8 +d==2661693 &&
162*9 ^5+x*9 ^4+a*9 ^3+b*9 ^2+c*9 +d==5237550 &&
162*10^5+x*10^4+a*10^3+b*10^2+c*10+d==9496287 &&
162*11^5+x*11^4+a*11^3+b*11^2+c*11+d==16149624&&
162*12^5+x*12^4+a*12^3+b*12^2+c*12+d==26085537,
{x,a,b,c,d}]
Out[15]= {{x -> -756, a -> 738, b -> 1416, c -> -2343, d -> 117}}
得出
wn34[n_]:=162 n^5-756 n^4+738 n^3+1416 n^2-2343 n+117
相關文章
- 尤拉計劃700:尤拉幣
- 尤拉計劃622:洗牌
- 尤拉計劃698:123數
- 尤拉計劃719:拆分數
- 尤拉計劃699:三腳數
- 尤拉計劃706:三象數
- 尤拉計劃718:不可達數
- 尤拉計劃686:2的冪
- 尤拉計劃715:六元組
- 尤拉計劃709:偶數袋
- 尤拉計劃708:你只要2
- 尤拉計劃712:指數差
- 尤拉計劃749:近似冪和
- 尤拉計劃739:和的和
- 尤拉計劃751:串聯重合
- 尤拉計劃745:平方和
- 尤拉計劃717:取模公式之和公式
- 尤拉計劃722:慢收斂系列
- 尤拉計劃695:隨機長方形隨機
- 尤拉計劃694:立方滿因數
- 尤拉計劃725:數位之和數
- 尤拉計劃710:1百萬會員
- 尤拉計劃723:畢達哥拉斯四邊形
- 尤拉計劃697:隨機衰減序列隨機
- 尤拉計劃713:圖蘭熱水系統
- 尤拉計劃711:二進位制黑板
- 尤拉計劃748:倒丟蕃多方程
- 尤拉計劃747:三角披薩
- 尤拉計劃657:不完整的單詞
- 尤拉計劃721:無理數高次冪
- 尤拉計劃701:隨機連線區域隨機
- 尤拉計劃714:兩種數位的數
- 尤拉計劃658:不完整的單詞(2)
- 尤拉計劃735:2n^2的因數
- 尤拉計劃705:除數序列的逆轉次數
- 尤拉計劃621:把整數表示為三角數之和
- 尤拉計劃704:二項式係數中的2因數
- 尤拉方程