[指数型生成函数专练]chocolate,红色病毒问题,排列组合,字串数
文章目錄
- T1:chocolate
- 題目
- 題解
- code
- T2:“紅色病毒”問題
- 題目
- 題解
- code
- T3:排列組合
- 題目
- 題解
- code
- T4:字串數
- 題解
- code
T1:chocolate
題目
已幫大家翻譯了,不要去UVA或者luogu上面交,卡精度,
在2100年,ACM巧克力將成為世界上最受歡迎的食品之一。
“綠色,橙色,棕色,紅色…”,彩色糖衣殼也許是ACM巧克力最吸引人的特征。您見過多少種顏色?如今,據說ACM從二十四種顏色的調色板中進行選擇來繪制其美味的糖果。
一天,桑迪在一大包ACM巧克力上玩游戲,其中包含五種顏色(綠色,橙色,棕色,紅色和黃色)。每次他從包裝中取出一個巧克力并將其放在桌子上。如果桌子上有兩個顏色相同的巧克力,他會把它們都吃掉。他發現一件很有趣的事情,在大多數情況下,桌上總是有2或3塊巧克力。
現在,問題來了,如果包裝中有C種顏色的ACM巧克力(顏色均勻分布),那么從包裝中取出N顆巧克力后,桌上有M顆巧克力的概率是多少?您可以編寫一個程序來解決嗎?
輸入
此問題的輸入文件包含幾個測試用例,每行一個
對于每種情況,都有三個非負整數:C(C <= 100),N和M(N,M <= 1000000)
輸入由包含單個零的行終止。
輸出
輸出應該是每行一個實數,顯示每種情況的概率,四舍五入到小數點后三位
樣本輸入
5 100 2
0
樣本輸出
0.625
題解
首先我們由題意知道如果桌子上有兩個顏色相同的巧克力,會被吃掉,所以最后桌子上的巧克力一定是互不相同的,也就是有mmm種不同的糖果留在上面,所以我們可以特判當m>cm>cm>c時,是無解的
當m>nm>nm>n時,腦子也想得出來是無解的,一共就nnn顆,你從哪里變出m?nm-nm?n顆
再來每次都是兩顆兩顆地吃,所以n?mn-mn?m也就是吃的顆數一定是偶數,所以也可以特判一下
接下來進入母函數板塊
首先是
前面提到過最后剩在桌上的糖果一定都是互不相同的,剩mmm顆,也就是剩mmm種,那么這mmm種糖果拿的數量一定是奇數(最后剩下一個不能吃),剩下的c?mc-mc?m種糖果拿的一定是偶數(都被兩兩吃掉),如果你不能理解就算了 ,且吃的順序不同算不同的方法加上是等概率,那么總情況就是cnc^ncn
我們考慮最普通的指數型函數
1+x1!+x22!+...+xnn!+...=ex1+\frac{x}{1!}+\frac{x^2}{2!}+...+\frac{x^n}{n!}+...=e^x1+1!x?+2!x2?+...+n!xn?+...=ex
奇數的糖果的話就要想辦法消掉x偶數項x^{偶數項}x偶數項,偶數的糖果就要想辦法消掉x奇數項x^{奇數項}x奇數項
奇數項:ex?e?x2\frac{e^x-e^{-x}}{2}2ex?e?x?
偶數項:ex+e?x2\frac{e^x+e^{-x}}{2}2ex+e?x?
不要慌,我們來帶一下e?x=1+?x1!+(?x)22!+...+(?x)nn!e^{-x}=1+\frac{-x}{1!}+\frac{(-x)^2}{2!}+...+\frac{(-x)^n}{n!}e?x=1+1!?x?+2!(?x)2?+...+n!(?x)n?
以奇數項為例,偶數項相信大家看完后會秒懂
ex?e?x2=(1?1)+(x?(?x))+(x2?(?x)2)+...+(xn?(?x)n)+...2\frac{e^x-e^{-x}}{2}=\frac{(1-1)+(x-(-x))+(x^2-(-x)^2)+...+(x^n-(-x)^n)+...}{2}2ex?e?x?=2(1?1)+(x?(?x))+(x2?(?x)2)+...+(xn?(?x)n)+...?=2x+2x3+2x5+...2=x+x3+x5+...=\frac{2x+2x^3+2x^5+...}{2}=x+x^3+x^5+...=22x+2x3+2x5+...?=x+x3+x5+...
那么把每一種糖果對應的母函數乘起來,即
(ex?e?x2)m+(ex?e?x2)c?m(\frac{e^x-e^{-x}}{2})^m+(\frac{e^x-e^{-x}}{2})^{c-m}(2ex?e?x?)m+(2ex?e?x?)c?m
運用二項式展開定理得到,看來我還得去學學這玩意兒
∑i=0m(?1)i?Cmi?e(m?i)?x?e?ix2m×∑i=0c?mCc?mi?e(c?m?i)x?e?ix2c?m\frac{\sum_{i=0}^m\ (-1)^i*C_m^i*e^{(m-i)*x}*e^{-ix}}{2^m}×\frac{\sum_{i=0}^{c-m}C_{c-m}^i*e^{(c-m-i)x}*e^{-ix}}{2^{c-m}}2m∑i=0m??(?1)i?Cmi??e(m?i)?x?e?ix?×2c?m∑i=0c?m?Cc?mi??e(c?m?i)x?e?ix?
∑i=0m(?1)i?Cmi?e(m?2i)x×∑i=0c?mCc?mi?e(c?m?2i)x2c\frac{\sum_{i=0}^m(-1)^i*C_m^i*e^{(m-2i)x}×\sum_{i=0}^{c-m}C_{c-m}^i*e^{(c-m-2i)x}}{2^c}2c∑i=0m?(?1)i?Cmi??e(m?2i)x×∑i=0c?m?Cc?mi??e(c?m?2i)x?
我們先把分母放一放,先只看分子,對其進行化簡
∑i=0m∑j=0c?m(?1)i?Cmi?Cc?mj?e(c?2i?2j)x\sum_{i=0}^m\sum_{j=0}^{c-m}(-1)^i*C_m^i*C_{c-m}^j*e^{(c-2i-2j)x}i=0∑m?j=0∑c?m?(?1)i?Cmi??Cc?mj??e(c?2i?2j)x
將這個的封閉式展開,變成
∑k=0∞∑i≤0≤m,j≤0≤c?m(?1)i?Cmi?Cc?mj?(c?2i?2j)kk!?xk\sum_{k=0}^∞\frac{\sum_{i\le0\le m,j\le0\le c-m}(-1)^i*C_m^i*C_{c-m}^j*{(c-2i-2j)^k}}{k!}*x^kk=0∑∞?k!∑i≤0≤m,j≤0≤c?m?(?1)i?Cmi??Cc?mj??(c?2i?2j)k??xk
但是這里我們不能忘記上面的分母和總情況2c,cn2^c,c^n2c,cn,最后剩下的是哪mmm種,還有一個CcmC_c^mCcm?
所以最后第nnn項的系數就是Ccm2c?cn?∑i≤0≤m,j≤0≤c?m(?1)i?Cmi?Cc?mj?(c?2i?2j)k\frac{C_c^m}{2^c*c^n}*\sum_{i\le0\le m,j\le0\le c-m}(-1)^i*C_m^i*C_{c-m}^j*{(c-2i-2j)^k}2c?cnCcm???i≤0≤m,j≤0≤c?m∑?(?1)i?Cmi??Cc?mj??(c?2i?2j)k
code
本來剛開始快速冪和組合數都不想開doubledoubledouble,但是同胞告訴我會炸intintint
T2:“紅色病毒”問題
題目
醫學界發現的新病毒因其蔓延速度和Internet上傳播的"紅色病毒"不相上下,被稱為"紅色病毒",經研究發現,該病毒及其變種的DNA的一條單鏈中,胞嘧啶,腺嘧啶均是成對出現的。
現在有一長度為N的字符串,滿足一下條件:
(1) 字符串僅由A,B,C,D四個字母組成;
(2) A出現偶數次(也可以不出現);
(3) C出現偶數次(也可以不出現);
計算滿足條件的字符串個數.
當N=2時,所有滿足條件的字符串有如下6個:BB,BD,DB,DD,AA,CC.
由于這個數據肯能非常龐大,你只要給出最后兩位數字即可.
Input
每組輸入的第一行是一個整數T,表示測試實例的個數,下面是T行數據,每行一個整數N(1<=N<2^64),當T=0時結束.
Output
對于每個測試實例,輸出字符串個數的最后兩位,每組輸出后跟一個空行.
Sample Input
4
1
4
20
11
3
14
24
6
0
Sample Output
Case 1: 2
Case 2: 72
Case 3: 32
Case 4: 0
Case 1: 56
Case 2: 72
Case 3: 56
題解
對于B,DB,DB,D是沒有限制的,那么它們的生成函數則是普通型
1+x1!+x22!+x33!......=ex1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}......=e^x1+1!x?+2!x2?+3!x3?......=ex
而A,CA,CA,C的要求是必須出現偶數次,當然不出現也行,所以他們的生成函數就只能保留x偶數次x^{偶數次}x偶數次
1+x22!+x44!+......=ex+e?x21+\frac{x^2}{2!}+\frac{x^4}{4!}+......=\frac{e^x+e^{-x}}{2}1+2!x2?+4!x4?+......=2ex+e?x?
所以先寫T1的題解不是沒有邏輯的
將四個的生成函數閉形式相乘來化簡試試
(ex)2?(ex+e?x2)2=e2x?e2x+e?2x+24=e4x+2e2x+14(e^x)^2*(\frac{e^x+e^{-x}}{2})^2=e^{2x}*\frac{e^{2x}+e^{-2x}+2}{4}=\frac{e^{4x}+2e^{2x}+1}{4}(ex)2?(2ex+e?x?)2=e2x?4e2x+e?2x+2?=4e4x+2e2x+1?
然后還原成母函數
e4x=1+4x1!+(4x)22!+...(4x)nn!+....e^{4x}=1+\frac{4x}{1!}+\frac{(4x)^2}{2!}+...\frac{(4x)^n}{n!}+....e4x=1+1!4x?+2!(4x)2?+...n!(4x)n?+....
2e2x=2(1+2x1!+(2x)22!+...+(2x)nn!+...)=2+4x1!+8x2!+...+2(2x)nn!+...2e^{2x}=2(1+\frac{2x}{1!}+\frac{(2x)^2}{2!}+...+\frac{(2x)^n}{n!}+...)=2+\frac{4x}{1!}+\frac{8x}{2!}+...+\frac{2(2x)^n}{n!}+...2e2x=2(1+1!2x?+2!(2x)2?+...+n!(2x)n?+...)=2+1!4x?+2!8x?+...+n!2(2x)n?+...
所以
e4x+2e2x+14=14?(4+4x+2?2x1!+(4x)2+2?(2x)22!+...+(4x)n+2(2n)nn!)+...\frac{e^{4x}+2e^{2x}+1}{4}=\frac{1}{4}*(4+\frac{4x+2*2x}{1!}+\frac{(4x)^2+2*(2x)^2}{2!}+...+\frac{(4x)^n+2(2n)^n}{n!})+...4e4x+2e2x+1?=41??(4+1!4x+2?2x?+2!(4x)2+2?(2x)2?+...+n!(4x)n+2(2n)n?)+...
=14?(4+(4+2?2)x1!+(42+2?22)x22!+...(4n+2?2n)xnn!+...)=\frac{1}{4}*(4+(4+2*2)\frac{x}{1!}+(4^2+2*2^2)\frac{x^2}{2!}+...(4^n+2*2^n)\frac{x^n}{n!}+...)=41??(4+(4+2?2)1!x?+(42+2?22)2!x2?+...(4n+2?2n)n!xn?+...)
常數項是第零項,把14\frac{1}{4}41?乘進去,所以第nnn項的系數應該是
14?(4n+2?2n)=4n?1+2n?1\frac{1}{4}*(4^{n}+2*2^{n})=4^{n-1}+2^{n-1}41??(4n+2?2n)=4n?1+2n?1
code
#include <cstdio> #include <iostream> using namespace std; #define mod 100 #define LL unsigned long long LL n;LL qkpow ( LL x, LL y ) {LL ans = 1;while ( y ) {if ( y & 1 )ans = ans * x % mod;x = x * x % mod;y >>= 1;}return ans; }int main() {int T; while ( scanf ( "%d", &T ) && T != 0 ) {int Case = 0;while ( T -- ) {cin >> n;printf ( "Case %d: %lld\n", ++ Case, ( qkpow ( 2, n - 1 ) + qkpow ( 4, n - 1 ) ) % mod ); }printf ( "\n" ); }return 0; }T3:排列組合
題目
有n種物品,并且知道每種物品的數量。要求從中選出m件物品的排列數。例如有兩種物品A,B,并且數量都是1,從中選2件物品,則排列有"AB","BA"兩種。
Input
每組輸入數據有兩行,第一行是二個數n,m(1<=m,n<=10),表示物品數,第二行有n個數,分別表示這n件物品的數量。
Output
對應每組數據輸出排列數。(任何運算不會超出2^31的范圍)
Sample Input
2 2
1 1
Sample Output
2
題解
我們對于每一種物品數,都可以寫出其生成函數
i∈[1,n],1+x1!+x22!+x33!+...+xnum[i]num[i]!i∈[1,n],1+\frac{x}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}+...+\frac{x^{num[i]}}{num[i]!}i∈[1,n],1+1!x?+2!x2?+3!x3?+...+num[i]!xnum[i]?
設dp[j]dp[j]dp[j]表示選了jjj個物品的排列數,那么對于第iii種物品而言,我們枚舉該種物品選的個數是k∈[1,num[i]]k∈[1,num[i]]k∈[1,num[i]],那么排列數就要加上kkk個物品的排列數,但是因為它們是一種,順序沒有用,所以要除掉k!k!k!
于是可以寫出轉移方程式dp[j+k]=dp[j+k]+dp′[j]/k!dp[j+k]=dp[j+k]+dp'[j]/k!dp[j+k]=dp[j+k]+dp′[j]/k!
code
這就像是一種模板了。。
#include <cstdio> #include <cstring> #define MAXN 15 int n, m; int fac[MAXN], num[MAXN]; double dp1[MAXN], dp2[MAXN];void init () {fac[0] = fac[1] = 1;for ( int i = 2;i < MAXN;i ++ )fac[i] = i * fac[i - 1]; }int main() {init();while ( ~ scanf ( "%d %d", &n, &m ) ) {for ( int i = 1;i <= n;i ++ )scanf ( "%d", &num[i] );memset ( dp1, 0, sizeof ( dp1 ) );memset ( dp2, 0, sizeof ( dp2 ) );for ( int i = 0;i <= num[1];i ++ )dp2[i] = 1.0 / fac[i];for ( int i = 2;i <= n;i ++ ) {for ( int j = 0;j <= m;j ++ )for ( int k = 0;k <= num[i];k ++ )if ( j + k > m )break;elsedp1[j + k] += dp2[j] / fac[k];for ( int j = 0;j <= m;j ++ ) {dp2[j] = dp1[j];dp1[j] = 0;}}printf ( "%.0lf\n", dp2[m] * fac[m] );}return 0; }T4:字串數
一個A和兩個B一共可以組成三種字符串:“ABB”,“BAB”,“BBA”.
給定若干字母和它們相應的個數,計算一共可以組成多少個不同的字符串.
Input
每組測試數據分兩行,第一行為n(1<=n<=26),表示不同字母的個數,第二行為n個數A1,A2,…,An(1<=Ai<=12),表示每種字母的個數.測試數據以n=0為結束.
Output
對于每一組測試數據,輸出一個m,表示一共有多少種字符串.
Sample Input
2
1 2
3
2 2 2
0
Sample Output
3
90
題解
這道題跟上面第三題有點相似,我們可以先看對于nnn個字符,一共可以拼湊出n!n!n!個字符串
但是我們知道如果有兩個AAA那么A0A1A_0A_1A0?A1?和A1A0A_1A_0A1?A0?我們是看不出來的,那么就應該排除掉它們的影響
所以這道題的公式就是n!A0!A1!...An!\frac{n!}{A_0!A_1!...A_n!}A0?!A1?!...An?!n!?
其實這道題的本質是卡我們的高精,哎~具體的代碼理解在codecodecode里面有詳解,你一定會看得懂的
code
#include <cstdio> #include <cstring> #define MAXN 30 #define MAX 1000 int n, len; int A[MAXN]; int res[MAX];void Res_bit () { for ( int i = 0;i < len;i ++ )if ( res[i] > 9 ) {if ( i == len - 1 )len ++;res[i + 1] += res[i] / 10;res[i] %= 10;} }void Fac ( int x ) {res[0] = x;len = 1;Res_bit();while ( x > 2 ) { //1是不必要乘的,0是不能乘的 //這個條件的下限就是x=3,走進去就變成了2,當x=2時就不必要了 x --; //大數乘法其實跟豎式乘法是一樣的 //我們算A*B是用B的個位依次去乘A的每一位加上B的十位去乘A的每一位的結果...以此類推for ( int i = 0;i < len;i ++ )res[i] *= x;Res_bit ();//每一次都要進行大數進位 } }void div ( int x ) { //除法也可以用豎式來理解,從最高位開始除 //除不動就往下一位(商0),除得動就把余數傳給下一位 for ( int i = len - 1;i >= 0;i -- )if ( res[i] < x ) { //有的人可能會疑問感覺每次除法都只少了一位 //其實不然,在i循環減小時,如果是從最高位開始縮位 //len其實是同步減小了的,上面的進位同理 if ( i == len - 1 )len --;res[i - 1] += res[i] * 10;res[i] = 0;}else {if ( i > 0 )res[i - 1] += ( res[i] % x ) * 10;res[i] = res[i] / x;} }int main() {while ( scanf ( "%d", &n ) && n ) {int tot = 0;for ( int i = 1;i <= n;i ++ ) {scanf ( "%d", &A[i] );tot += A[i];}Fac ( tot );for ( int i = 1;i <= n;i ++ )for ( int j = 2;j <= A[i];j ++ )div ( j );for ( int i = len - 1;i >= 0;i -- )printf ( "%d", res[i] );printf ( "\n" );memset ( res, 0, sizeof ( res ) );}return 0; }
我好想寫得順序出了問題,我是fu應該先寫生成函數的學習博客,然后再寫題解
總結
以上是生活随笔為你收集整理的[指数型生成函数专练]chocolate,红色病毒问题,排列组合,字串数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聂宇晟谈静的小说 小说讲述一个怎样的故事
- 下一篇: [TJOI2019]唱、跳、rap和篮球