1. 程式人生 > >HDU 2512 一卡通大冒險(第二類斯特林數+貝爾數)

HDU 2512 一卡通大冒險(第二類斯特林數+貝爾數)

題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=2512

題目大意:
因為長期鑽研演算法, 無暇顧及個人問題,BUAA ACM/ICPC 訓練小組的帥哥們大部分都是單身。某天,他們在機房商量一個絕妙的計劃"一卡通大冒險"。這個計劃是由wf最先提出來的,計劃的內容是,把自己的聯絡方式寫在校園一卡通的背面,然後故意將自己的卡"遺失"在某處(如水房,TD,食堂,主M。。。。)他們希望能有MM看到他們遺失卡,能主動跟他們聯絡,這樣就有機會請MM吃飯了。他們決定將自己的一卡通夾在基本相同的書裡,然後再將書遺失到校園的各個角落。正當大家為這個絕妙的計劃叫好時,大家想到一個問題。很明顯,如果只有一張一卡通,那麼只有一種方法,即,將其夾入一本書中。當有兩張一卡通時,就有了兩種選擇,即,將兩張一卡通夾在一本書裡,或者分開夾在不同的書裡。當有三張一卡通時,他們就有了5種選擇,即:
{{A},{B},{C}} , {{A,B},{C}}, {{B,C},{A}}, {{A,C},{B}} ,{{A,B,C}} 於是,
這個邪惡計劃的組織者wf希望瞭解,如果ACM訓練對裡有n位帥哥(即有N張一卡通),那麼要把這些一卡通夾到書裡有多少種不同的方法。

解題思路:
轉自:https://blog.csdn.net/qpswwww/article/details/44974693
第一類斯特林數s2[i][j]=將j個互不相同的物品劃分成j個非空集合的方案數。
s2[i][j]=s2[i?1][j?1]+js2[i?1][j]
遞推式的解釋:對於第i個物品有兩種情況:
1、前i?1個物品已經劃分成了j?1個非空集合,第i個物品單獨構成第j個集合。
2、前i?1個物品已經劃分成了j個非空集合,第i個物品可以選擇放入j個集合當中之一,共j個方案,因此是js2[i?1][j]。

貝爾數bell[i]=i個互不相同的物品,劃分成若干個非空集合的方案數。
bell[i]=∑k=0is2[i][k]
這個式子非常顯然,即列舉劃分成k個非空集合,對s2[i][k]求和即可得到貝爾數。

程式碼

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int N=2e3+5;
 6 const int MOD=1e3;
 7 
 8 int    ans[N];
 9 int dp[N][N];//dp[i][j]表示將前i個數分j組的方案數 
10 
11 int main(){
12     dp[1][1]=1;
13     for(int i=2;i<N;i++){
14 for(int j=1;j<=i;j++){ 15 dp[i][j]=(dp[i-1][j-1]+dp[i-1][j]*j)%MOD; 16 } 17 } 18 for(int i=1;i<N;i++){ 19 for(int j=1;j<=i;j++){ 20 ans[i]=(ans[i]+dp[i][j])%MOD; 21 } 22 } 23 int n; 24 cin>>n; 25 while(n--){ 26 int x; 27 cin>>x; 28 cout<<ans[x]<<endl; 29 } 30 return 0; 31 }