1. 程式人生 > >Round Numbers--楊輝三角,組合數學

Round Numbers--楊輝三角,組合數學

大致題意:

輸入兩個十進位制正整數ab,求閉區間 [a ,b] 內有多少個Round number

所謂的Round Number就是把一個十進位制數轉換為一個無符號二進位制數,若該二進位制數中0的個數大於等於1的個數,則它就是一個Round Number

注意,轉換所得的二進位制數,最高位必然是1,最高位的前面不允許有0

規定輸入範圍: 1<= a <b<=2E

用組合做

很猥瑣的題,我首先說說猥瑣的地方,再說說解題思路,有四點很猥瑣:

1)規定輸入範圍: 1<= a <b<=20E

輸入的數是一個接近大數的非大數,int可以儲存

網上看很多同學都說要用到精度,其實完全沒必要,int

能表示21E+的整數,精確的int極限能表示的正整數為2147483647,

但是即使這樣,面對這題也不能鬆懈啊!bin[]邊界的最小值為35 !!。

2bin[]陣列若果定義為區域性陣列,等著WA吧!

我找不到任何原因為什麼會這樣,bin不管是全域性定義還是區域性定義,本地是完全AC的,上傳就出問題了,區域性WA,全域性AC

人家有強權,我被迫把傳參del掉,把bin改為全域性,鬱悶!猥瑣!

3)組合數打表,同(1)的猥瑣,c[][]邊界的最小值為33,就是說如果定義組合表的大小比

c[33][33]小的,就等著RE

還有就是這個演算法有一個違背常識的處理,要把c[0][0]=1,不然某些最終結果會少1

4)輸入不能用迴圈輸入while(cin>>…),不然你就等著OLE (就是Output Limit Excessed,很少見吧!)。不知道資料庫是怎麼回事,輸入竟然不會根據讀取資料結束而結束,而是無限輸出最後一次輸入所得的結果……老老實實一次輸出就end file吧!

解題思路:

組合數學題,不知道為什麼會被歸類到遞推數學,可能是因為楊輝三角和組合數之間的關係。。。

我根據我寫的程式講解好了

要知道閉區間 [a ,b] 內有多少個Round number,只需要分別求出

閉區間 [0 ,a] 內有TRN

閉區間 [0 ,b+1] 內有SRN

再用 S – T 就是閉區間 [a ,b] 

內的RN數了

至於為什麼是 b+1,因為對於閉區間 [0 ,k] ,我下面要說的演算法求出的是比k小的RN數,就是說不管 k是不是RN, 都沒有被計算在內,所以若要把閉區間[a ,b]的邊界ab都計算在內,就要用上述的處理方法。

現在問題的關鍵就是如何求[0 ,k]內的RN數了

首先要把k轉化為二進位制數bin-k,並記錄其位數(長度)len

那麼首先計算長度小於lenRN數有多少(由於這些數長度小於len,那麼他們的值一定小於k,因此在進行組合時就無需考慮組合所得的數與k之間的大小了)

for(i=1;i<bin[0]-1;i++)         //bin[0]記錄的是二進位制數的長度len

              for(j=i/2+1;j<=i;j++)

                     sum+=c[i][j];

可以看到,i<len-1 ,之所以減1,是因為這些長度比len小的數,最高位一定是1,那麼剩下可供放入數字的位數就要再減少一個了

這條程式得到的sum


1表示當前處理的二進位制數的最高位,X表示該二進位制數待放入數字的位

顯然這段程式把二進位制數0  排除在外了,這個是最終結果沒有影響的,因為最後要把區間[a , b]首尾相減,0存不存在都一樣了。

然後計算長度等於lenRN數有多少(由於這些數長度等於len,那麼他們的值可能小於k,可能大於k,因此在進行組合時就要考慮組合所得的數與k之間的大小了)

int zero=0;  //從高位向低位搜尋過程中出現0的位的個數

       for(i=bin[0]-1;i>=1;i--)

              if(bin[i])   //當前位為1

                     for(j=(bin[0]+1)/2-(zero+1);j<=i-1;j++)

                            sum+=c[i-1][j];

              else

                     zero++;

之所以初始化i=bin[0]-1,是因為bin[]是逆向存放k的二進位制的,因此要從高位向低位搜尋,就要從bin[]後面開始,而要 bin[0]-1 是因為預設以後組合的數長度為len,且最高位為1,因此最高位不再搜尋了。

那麼問題的關鍵就是怎樣使得以後組合的數小於k

這個很簡單:

從高位到低位搜尋過程中,遇到當前位為0,則不處理,但要用計數器zero累計當前0出現的次數

遇到當前位為1,則先把它看做為0zero+1,那麼此時當前位後面的所有低位任意組合都會比k小,找出這些組合中RN的個數,統計完畢後把當前位恢復為原來的1,然後zero-1,繼續向低位搜尋

那麼問題就剩下噹噹前位為1時,把它看做0之後,怎樣去組合後面的數了

此時組合要考慮2個方面:

(1)       當前位置i後面允許組合的低位有多少個,我的程式由於bin是從bin[1]開始儲存二進位制數的,因此當前位置i後面允許組合的低位有i-1

(2)       組合前必須要除去前面已出現的0的個數zero

我的程式中初始化j=(bin[0]+1)/2-(zero+1) j本來初始化為(bin[0]+1)/2就可以了,表示對於長度為bin[0]的二進位制數,當其長度為偶數時,至少其長度一半的位數為0,它才是RN,當其長度為奇數時,至少其長度一半+1的位數為0,它才是RN

但是現在還必須考慮前面出現了多少個0,根據前面出現的0的個數,j的至少取值會相應地減少。  -(zero+1) ,之所以+1,是因為要把當前位bin[i]看做0

然後到了最後,剩下一個問題就是怎樣得到每一個的值,這個我發現很多同學都是利用打表做的,利用的就是組合數與楊輝三角的關係(建立一個二維陣列C[n]

就能看到他們之間關係密切啊!區別就是頂點的值,楊輝三角為1,組合數為0

其實這個“關係”是有數學公式的

好好體會一下吧!

其實組合數也可以直接用計算方法做(n的規模可以至少擴充套件到1000),不過這裡n的規模只有26,打表應該是更快的,有興趣學習用計算方法做組合數的同學可以聯絡我,這個要用另外的數學方法處理。

QQ289065406    O(_)O哈哈~

//Memory Time 
//224K   16MS  

#include<iostream>
using namespace std;

int c[33][33]={0};
int bin[35];  //十進位制n的二進位制數

/*打表,計算nCm*/

void play_table(void)
{
    for(int i=0;i<=32;i++)
        for(int j=0;j<=i;j++)
            if(!j || i==j)
                c[i][j]=1;
            else
                c[i][j]=c[i-1][j-1]+c[i-1][j];
//    c[0][0]=0;
    return;
}

/*十進位制n轉換二進位制,逆序存放到bin[]*/

void dec_to_bin(int n)
{
    bin[0]=0;   //b[0]是二進位制數的長度
    while(n)
    {
        bin[++bin[0]]=n%2;
        n/=2;
    }
    return;
}

/*計算比十進位制數n小的所有RN數*/

int round(int n)
{
    int i,j;
    int sum=0;  //比十進位制數n小的所有RN數
    dec_to_bin(n);

    /*計算長度小於bin[0]的所有二進位制數中RN的個數*/

    for(i=1;i<bin[0]-1;i++)
        for(j=i/2+1;j<=i;j++)
            sum+=c[i][j];

    /*計算長度等於bin[0]的所有二進位制數中RN的個數*/

    int zero=0;  //從高位向低位搜尋過程中出現0的位的個數
    for(i=bin[0]-1;i>=1;i--)
        if(bin[i])   //當前位為1
            for(j=(bin[0]+1)/2-(zero+1);j<=i-1;j++)
                sum+=c[i-1][j];
        else
            zero++;

    return sum;
}

int main(void)
{
    play_table();

    int a,b;
    cin>>a>>b;
    cout<<round(b+1)-round(a)<<endl;

    return 0;
}

 

必須的大神,這個題想了兩天了,知道和數學有關係,就是沒想出來怎麼做,去搜了部落格,大神解釋的很清楚,每一步都很到位,我不懂得地方大神都有講解,比如for迴圈裡面的開始結束條件,必須的聰明啊,大神就是厲害,膜拜中。。。。第一次轉載部落格,不太會弄,不好的地方多多見諒,反正都已經不好了,你也打不到我是不是,淡定。

繼續學習!

相關推薦

Round Numbers--三角組合數學

大致題意: 輸入兩個十進位制正整數a和b,求閉區間 [a ,b] 內有多少個Round number 所謂的Round Number就是把一個十進位制數轉換為一個無符號二進位制數,若該二進位制數中0的個數大於等於1的個數,則它就是一個Round Number 注意,轉換所得的二進位制數,最高位必然是1,最

Combinatorics——HDUOJ 1799 - 迴圈多少次?(三角 - 排列組合

原題: Problem Description 我們知道,在程式設計中,我們時常需要考慮到時間複雜度,特別是對於迴圈的部分。例如, 如果程式碼中出現 for( i=1; i<=n; i++) OP ; 那麼做了n次OP運算,如果程式

初夏小談:判斷運動員名次三角日本謀殺案(斷案大師)

今天給大家帶來三道經典題型。 5位運動員參加了10米臺跳水比賽,有人讓他們預測比賽結果 A選手說:B第二,我第三; B選手說:我第二,E第四; C選手說:我第一,D第二; D選手說:C最後,我第三; E選手說:我第四,A第一; 比賽結束後,每位選手都說對了一半,請程式設計確定比賽的名次。 #

藍橋杯(java):數列特徵查詢整數三角特殊的數字迴文數

人生無趣,生活不易,一起找點樂子吧。     數列特徵: 問題描述 給出n個數,找出這n個數的最大值,最小值,和。 輸入格式 第一行為整數n,表示數的個數。 第二行有n個數,為給定的n個數,每個數的絕對值都小於10000。 輸出格式 輸出三行,每行一個整

Python實現三角超詳細!

巧妙實現楊輝三角程式碼 def triangles(): N=[1]   #初始化為[1],楊輝三角的每一行為一個list while True: yield N  #yield 實現記錄功能,沒有下一個next將跳出迴圈, S=N[:]   #將l

利用三角組合程式碼

//在資料型別內運算可以求得正確結果,程式碼有冗餘,由三角矩陣的兩列可以得出全部組合數列,暫時先用這種笨拙的方法 #include <iostream> using namespace std; int main(int argc, char* argv) {

控制檯列印N行三角並算出總和

Scanner src = new Scanner(System.in);System.out.println("請輸入楊輝三角的行數: ");int total = 0;int total1 = 0;int a  =src.nextInt();//定義一個二維陣列int[]

poj 3252 Round Numbers三角求組合數)

題目連結:poj 3252 題意:給出範圍為 [a , b] 的區間,問在這區間內的每個數字,假如它的二進位制位0的個數大於1的個數,就說明它是Round Numbers,問你有多少個Round Numbers數? 題解:首先楊輝三角求組合數學,見程式碼。   ///此

Codeforces Round #439 (Div. 2)(補題) A模擬+set B 數學 C dp or 三角組合數

— This is not playing but duty as allies of justice, Nii-chan! — Not allies but justice itself, Onii-chan! With hands joined, go everywhere at a speed fas

求第n行三角(n很大取模

int 為什麽不能 style code 為我 max sin clas pan 1 #include <iostream> 2 #include <cstdio> 3 4 using namespace std; 5 typedef

Java小題通過JNI調用本地C++共享庫中的對應方法實現三角的繪制

question 文件夾 path ron variable iostream ring printf spl 1.在Eclipse中配置Javah,配置如下 位置是你javah.exe在你電腦磁盤上的路徑 位置:C:\Program Files\Java\jdk1.

列表 元組以及字符串等字符結構以及三角的四種寫法

and part ascii碼 sha collect sci 有一個 第一個 [] 列表的 刪除復制等操作: list.remove(value) 刪除遇到的第一個值 list.pop(index)就地彈出某個值

*【CodeForces - 214D 】Numbers (dp組合數學

題幹: Furik loves writing all sorts of problems, especially such that he can't solve himself. You've got one of his problems, the one Furik gave to

三角的新的演算法Java初級

楊輝三角可以說是比較常見的程式問題,他的描述如下 楊輝三角形又稱Pascal三角形,它的第i+1行是(a+b)i的展開式的係數。 它的一個重要性質是:三角形中的每個數字等於它兩肩上的數字相加。 簡單的說就是他的每一行的第一個和最後一個等於1;中間的等於他的上以行的一個加上

帶有技巧的搜尋(洛谷數獨二進位制優先找列舉順序旅行商(寫了狀壓DP)數字三角(利用三角的係數)滑雪(記憶化))

ACM題集:https://blog.csdn.net/weixin_39778570/article/details/83187443 P1118 [USACO06FEB]數字三角形Backward Digit Su… 題目:https://www.luogu.org/problemn

編碼輸出圖形的思想:最重要的不是怎麼敲而是怎麼想!(三角和輸出金字塔!)

我們在程式設計練習初始階段總會碰到這樣的演算法題,輸出一個怎樣怎樣的圖形,達到什麼樣的效果,其實這樣的題都會有一個固定的思想。 首先要發現其中隱藏的規律,既然是輸出圖形,怎麼擺放一定是有規律的,要不然各種亂,一點規律沒有,這樣的題就一點意義都沒有了。所以拿到這種演算法題,

二維陣列空指標列印三角

需求:輸出楊輝三角 錯誤程式碼: import java.util.Scanner; class arraydemo3{ public static void main(String[] args){ Scanner sc = new Scanner(System.in); Syst

三角:非常容易理解的一種方式採用前面新增空格的形式實現對稱

package javacore; /** * @author lixw * @date created in 14:54 2018/12/17 */ public class Test02 { public static void main(String[] args) {

Recursive sequence 矩陣快速冪 + 組合數 非線性變線性利用到了組合數(三角求解快)

Farmer John likes to play mathematics games with his N cows. Recently, they are attracted by recursive sequences. In each turn, the cows would stand in a

輸出三角的前m行生成器的應用

m = int(input('請輸入行數:')) def triangles(): L = [1] while len(L) < = m: yield L