pku1430(第二類Stirling數 Sierpinski三角形)

來源:互聯網
上載者:User

http://162.105.81.212/JudgeOnline/problem?id=1430

此題是求第二類Stirling數S(n,k)的值,但是n,k的範圍非常大;下面是有關的資料,轉帖的;

 

 

 

首先介紹一下Sierpinski三角形:


       Sierpinski三角形是一種分形圖形,它是遞迴地構造的。最常見的構造方法如所示:把一個三角形分成四等份,挖掉中間那一份,然後繼續對另外三個三角形進行這樣的操作,並且無限地遞迴下去。每一次迭代後整個圖形的面積都會減小到原來的3/4,因此最終得到的圖形面積顯然為0。

       Sierpinski三角形的另一種構造方法如所示。把正方形分成四等份,去掉右下角的那一份,並且對另外三個正方形遞迴地操作下去。挖個幾次後把腦袋一歪,你就可以看到一個等腰直角的Sierpinski三角形。


        Sierpinski三角形&楊輝三角:

         當我在Matrix67部落格裡看到這個時真的感覺相當神奇,相當完美,太不可思議了。我們寫出8行或16行的楊輝三角,然後把其中的奇數和偶數標上不同的顏色,會發現楊輝三角(模2)與Sierpinski三角形時等價的。也就是二項式係數(組合數)的奇偶性竟然是個分型圖形。

        

       我們仔細觀察一下就可以發現通過楊輝三角奇偶表的前四行可以推出後四行來。可以看到楊輝三角的前四行是一個二階的Sierpinski三角形,它的第四行全是奇數。由於奇數加奇數等於偶數,那麼第五行中除了首尾兩項為1外其餘項都是偶數。而偶數加偶數還是偶數,因此中間那一排連續的偶數不斷地兩兩相加必然得到一個全是偶數項的“倒三角”。同時,第五行首尾的兩個1將分別產生兩個和楊輝三角前四行一樣的二階Sierpinski三角形。這正好組成了一個三階的Sierpinski三角形。顯然它的最末行仍然均為奇數,那麼對於更大規模的楊輝三角,結論將繼續成立。

        Sierpinski三角形與位元運算

         先提供一個程式可以輸出Sierpinski三角形。

#include <stdlib.h><br />#include <stdio.h><br />int main(int argc, char** argv)<br />{<br /> int i,j,n=(1<<5)-1;<br /> for (i=0;i<=n;i++)<br /> {<br /> for (j=0;j<=n;j++) printf((i&j)==j ? "#":" ");<br /> printf("/n");<br /> }<br /> return (EXIT_SUCCESS);<br />} 

 

輸出為:

這個程式告訴我們:在第i行第j列上打一個點若且唯若i and j=j,這樣最後得到的圖形就是一個Sierpinski三角形。這是為什麼呢?其實原因很簡單。把i和j寫成二進位(添加前置0使它們位元相同),由於j不能大於i,因此只有下面三種情況:
     情況一:
     i = 1?????
     j = 1?????
     問號部分i大於等於j
     i的問號部分記作i',j的問號部分記作j'。此時i and j=j若且唯若i' and j'=j'

     情況二:
     i = 1?????
     j = 0?????
     問號部分i大於等於j
     i的問號部分記作i',j的問號部分記作j'。此時i and j=j若且唯若i' and j'=j'

     情況三:
     i = 1?????
     j = 0?????
     問號部分i小於j
     此時i and j永遠不可能等於j。i' < j'意味著i'和j'中首次出現數字不同的那一位上前者為0,後者為1,那麼i和j做and運算時這一位的結果是0,與j不等。
     注意到,去掉一個位元最高位上的“1”,相當於從這個數中減去不超過它的最大的2的冪。觀察每一種情況中i,j和i',j'的實際位置,不難發現這三種情況遞迴地定義出了整個Sierpinski三角形。
     嘿!發現沒有,通過Sierpinski三角形證明了這個結論:組合數C(N,K)為奇數若且唯若N and K=K。

在維基百科上關於第二類Stirling數的介紹中有這樣一個公式:

        s(n,k)=c(z,w)(mod 2)

        z=n-ceil((k+1)/2);   w=floor((k-1)/2);

根據第二類Stirling數的遞推公式 s(n,k)=k*s(n-1,k)+s(n-1,k-1);分k為奇數和偶數的情況推一下就可以了,首先由於%2的操作,我想到了f(n,k) = s(n,k)%2,假設一個f函數。於是s(n,k) = k* s(n-1,k)+ s(n-1,k-1) ==>f(n,k) = s(n-1,k-1) (k為偶數); f(n,k) = f(n-1,k) + f(n-1,k-1)(k為奇數)。這樣就可以將k給去掉,最後就是計算f(n,k)%2即可,必須想到怎麼樣得到f(n,k)。也就是f(n,k)=c(n,k)%2。

首先根據n,k求出z,w,再判斷(z&w)是否等於w就可以了。但是自己看完也想了很久還是雲裡霧裡的……#include<iostream><br />using namespace std;<br />int main() //維基百科上面的公式s(n,k)=c(z,w)%2; c(z,w)表示組合數運算,<br />{ //z= n - ceil((k+1)/2); w= floor((k-1)/2);<br />int t,n,k,z,w;<br />scanf("%d",&t);<br />while(t-- && scanf("%d%d",&n,&k))<br />{<br />w = (k-1)/2;//求的是floor((k-1)/2)的值,就是向下取整;<br />z = n - k + w; //求的是n - ceil((k+1)/2)的值,就是向上取整;<br />//cout<<w<<" "<<z<<endl;<br />if((z & w) == w)<br />printf("1/n");<br />else<br />printf("0/n");<br />}<br />return 0;<br />} 

 

 

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.