題目:http://acm.hdu.edu.cn/showPRoblem.php?pid=1133
題目的意思是,m個人只有50元錢,n個人只有100元整錢,票價50元/人.現在售票廳沒錢,只有50元錢的人可以不用找錢順利買票,而拿著100元整錢的人只有在前面有50元的情況下才能買票,因為只有這樣,才能找零50元.所有的人能否買票和排隊的方式有一定關系,問使得所有的人能夠順利買票的排隊方式有多少種?
上述問題可以抽象為下面的數學模型,數學模型及求解過程如下圖:

本題中每個人是不一樣的,所以本題的最終結果:排列的總數應該為U*n!*m!,即:

下面本題的目標就是按照下面思路編程求解:
1.若m<n,則結果為0
2.若m>=n,則結果就是U*n!*m!.
題目m,n<=100,100!是一個很大的數,已有的數據類型無法存儲,可以用數組存儲,模擬【乘法】和【除法】.
【乘法】的過程見:http://blog.csdn.net/ten_sory/article/details/60476570
【除法】較復雜,這里可以【避免除法】.注意分母只有(m+1),當n>=1的時候,(m+n)!包含(m+1)一項,直接在計算這個階乘的時候,不計算這一項即可.當n=0的時候,本題的結果為m!.
C++代碼如下:
#include<iostream>#include<string.h>using namespace std;void Multiply(int a[],int z)//大數a[]和小數z相乘,結果存儲在a[]中{ int maxn = 2000; int c = 0; for(int j=maxn-1;j>=0;j--)//用z乘以a[]的每一位 { int x = a[j] * z + c; a[j] = x % 10; c = x / 10; }}int main(){ int m,n,num=0; while(1) { cin >> m >> n; if(!m && !n) break; cout << "Test #" << ++num << ":" << endl; if(m<n)//m<n,沒有符號條件的排列 { cout << 0 << endl; continue; } const int maxn = 2000; int a[maxn],i,j; memset(a,0,sizeof(a)); a[maxn-1] = 1; if(n==0)//此時全是拿50元的人,直接輸出m!的結果 for(i=2;i<=m+n;i++)//計算m! Multiply(a,i); else if(n>=1)//此時按照公式計算,避開除法 { for(i=2;i<=m+n;i++) if(i!=m+1)//如果,某一項恰好是分母(m+1),則不乘以這一項 Multiply(a,i); Multiply(a,m-n+1);//根據公式,最后還要乘以(m-n+1)一項 } for(i=0;i<maxn;i++) if(a[i])//從i開始,非零 break; for(j=i;j<maxn;j++)//輸出 cout << a[j]; cout << endl; } return 0;}上述代碼,提交可以通過.
小結:
1.關于【卡特蘭數】
當m=n時,U的值就是n-卡特蘭數,如下圖:
更多關于卡特蘭數的性質和應用,參看:http://blog.csdn.net/zhangmh93425/article/details/44677891
2.避開除法
本題有一個小技巧,就是避開了除法,因為當n>=1的時候,分子(m+n)!中一定有一項為(m+1),避開這一項,相當于先乘以這一項,再除以這一項.如此避開了麻煩的除法,但是要注意,當n=0的時候,(m+n)!中沒有(m+1)這一項,則需要另作處理.
新聞熱點
疑難解答