問題 A: 集合劃分問題
題目描述
包含n個元素的集合,可以劃分爲若干個非空子集。例如,當n=3時,集合{1,2,3} 可以構造如下五個劃分:
{1,2,3} {1},{2},{3}
{1,2},{3} {1,3},{2} {1},{2,3}
請設計程序,計算包含n個元素的集合可以構造多少個不同的劃分。
輸入
一個整數n,(1<=n<=25)
輸出
一個整數
樣例輸入
1
樣例輸出
1
思想:①貝爾數,集合劃分是貝爾數的一個問題。②DP,dp[i][j]代表是將i個數分到j個集合內
dp[i][j]=dp[i-1][j]*j+dp[i-1][j-1] 意思是當前有i-1個數和j個集合,你將第i個數放到j個集合中的一個有個j中選擇,或者是當前這個數單獨放一個集合。
long long B[30];
long long T[30];
const int N = 26;
void Bell()
{
B[0] = 1;
B[1] = 1;
T[0] = 1;
for(int i=2;i<N;i++)
{
T[i-1] = B[i-1];
for(int j=i-2;j>=0;j--)
T[j] = (T[j]+T[j+1]);
B[i] = T[0];
}
}
int main()
{
Bell();
int temp;
scanf("%d",&temp);
printf("%lld\n",B[temp]);
return 0;
}
問題 B: 樓梯臺階問題
題目描述
有一樓梯共M級,剛開始時你在第一級,若每次只能跨上一級或二級,要走上第M級,共有多少種走法?
輸入
第一行一個整數T,表示測試組數。
接下來T行每行一個整數M(1<=M<=40)
輸出
輸出T行
每行一個整數
樣例輸入
1
4
樣例輸出
3
思想:第 i 階臺階由i-1跨一步或者i-2跨2步過來,所以dp[i]=dp[i-1]+dp[i-2].預處理下dp[1] dp[2] dp[3]即可
對於第一階臺階是0還是1,假如考慮在1不動算一種情況就是1 否則就就是0
問題 C: 小蜜蜂
題目描述
有一隻經過訓練的蜜蜂只能爬向右側相鄰的蜂房,不能反向爬行。請編程計算蜜蜂從蜂房a爬到蜂房b的可能路線數。其中,蜂房的結構如下所示。
輸入
一個整數T表示測試組數。
接下來T行,每行兩個整數a和b(0<a<b<50)
輸出
T行
每行一個整數
樣例輸入
2
1 2
3 6
樣例輸出
1
3
思想:考慮下對於任何點來說它只能通過相鄰的2個過來,所以就可以考慮枚舉下每個點的貢獻,每個點只能對於+1 +2有貢獻.
ll dp[60];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(dp,0,sizeof(dp));
int a,b;
scanf("%d%d",&a,&b);
dp[a+1]=1;
dp[a+2]=2;
for(int i=a+3;i<=b;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
printf("%d\n",dp[b]);
}
return 0;
}
問題 D: 切面條問題
題目描述
一根高筋拉麪,中間切一刀,可以得到2根麪條。如果先對摺1次,中間切一刀,可以得到3根麪條。如果連續對摺2次,中間切一刀,可以得到5根麪條。那麼,連續對摺n次,中間切一刀,會得到多少麪條呢?
輸入
一個整數n(1<=n<=1000000)
輸出
一個整數,注意,由於答案非常大,要求你輸出答案模除1000000007之後的結果
樣例輸入
3
樣例輸出
9
思想:單獨考慮的每一個話,穩的T,可以將每個點可以推出來一個很好推的式子(毛線) 對於每個n來說 他就等於2^n+1.
無論是線性跑n還是快速冪都OK
問題 E: 整數劃分問題
題目描述
計算將一個給定的正整數劃分爲一系列正整數的和的方案數,稱爲整數的劃分問題,例如,當給定正整數爲6時,可以有如下劃分:
6=6;
6=5+1;
6=4+2=4+1+1;
6=3+3=3+2+1=3+1+1+1;
6=2+2+2=2+2+1+1=2+1+1+1+1;
6=1+1+1+1+1+1+1。
如果用f(n)代表正整數n的劃分數,則f(6)=11
現在,給你數字n,要求你計算f(n)
輸入
一個整數n
輸出
輸出f(n)。注意,由於答案非常大,你的答案需要輸出模除1000000007之後的結果
樣例輸入
6
樣例輸出
11
思想:母函數算法的模板題,如果看到此博客可以學一下母函數,會在其中註釋代碼,仍有不懂可以提問。
const long long mod = 1e9+7;
const int maxn= 1e5+5;
long long c1[maxn];
long long c2[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<=n;i++)//c1是儲存每個的結果 c2是每次計算的結果
{
c1[i]=1; //初始化對於每一項的係數都是1
c2[i]=0;
}
for(int i=2;i<=n;i++)//枚舉項數 總共有n個式子
{
for(int j=0;j<=n;j++)//枚舉前邊的到的所有項數
{
for(int k=0;k+j<=n;k+=i)//對於第i個式子的每個式子的係數 所以是每次加i
c2[k+j]=(c1[j] + c2[k+j])%mod; //k+j是乘完之後的次方
}
for(int k=0;k<=n;k++)//進行替換
{
c1[k]=c2[k];
c2[k]=0;
}
}
printf("%lld\n",c1[n]%mod);
return 0;
}
問題 F: 找單詞(母函數)
題目描述
假設有x1個字母A, x2個字母B,..... x26個字母Z,同時假設字母A的價值爲1,字母B的價值爲2,..... 字母Z的價值爲26。那麼,對於給定的字母,可以找到多少價值<=50的單詞呢?單詞的價值就是組成一個單詞的所有字母的價值之和,比如,單詞ACM的價值是1+3+14=18,單詞HDU的價值是8+4+21=33。(組成的單詞與排列順序無關,比如ACM與CMA認爲是同一個單詞)。
輸入
輸入首先是一個整數N,代表測試實例的個數。
然後包括N行數據,每行包括26個<=20的整數x1,x2,.....x26.
輸出
對於每個測試實例,請輸出能找到的總價值<=50的單詞數,每個實例的輸出佔一行。
樣例輸入
2
1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 2 6 2 10 2 2 5 6 1 0 2 7 0 2 2 7 5 10 6 10 2 10 6 1 9
樣例輸出
7
379297
思想:Hdu上的母函數的入門題。跟上邊的那個差不多隻是一些東西稍微改了下,思想還是一樣的,套上板子改改就好了。
對於母函數不懂的可以看上題題解,看懂在看此題更好。
const int maxn= 60;
long long c1[maxn];
long long c2[maxn];
int num[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
for(int i=1;i<=26;i++)//輸入每種的數量
scanf("%d",&num[i]);
memset(c1,0,sizeof(c1));
memset(c2,0,sizeof(c2));
for(int i=0;i<=num[0];i++)//將第一個的爲1 和 當初的那個n一樣
c1[i]=1;
for(int i=1;i<=26;i++)//枚舉項 就是那個26項
{
for(int j=0;j<=50;j++)//因爲要求不超過50 所以最大的權值應該是50
for(int k=0;k<=num[i]*i && k+j<=50;k+=i)//k的值應該小於等於最大的那個 而且 不會超過50
c2[k+j]=(c1[j] + c2[k+j]);
for(int k=0;k<=50;k++)
{
c1[k]=c2[k];
c2[k]=0;
}
}
long long ans=0;
for(int i=1;i<=50;i++)//所有的求一個和
ans+=c1[i];
printf("%lld\n",ans);
}
return 0;
}