2011ACM北京網絡預選賽 F Machine scheduling (BUPT 216)

2011ACM北京網絡預選賽 F Machine scheduling (BUPT 216)



這題比賽時候過得很糾結……最後還是學長過的……比賽時候腦子可能不夠清楚,一直WA……
首先,這個題要分成兩個部分解決:
第一部分:從n個東西里面取出r個,每個間距至少爲 k (1~K不行,1~K + 1行)
第二部分:將這r個東西分成至多m組,可以有空組
第二部分貌似好久之前搞OI的時候幹過……貼過來:




N球放在M個盒子裏,求共有多少种放法

但是有3個不同的條件 :N個球是否相同,M個盒子是否相同,是否允許有盒子空着





球和球


盒和盒


空盒


情況數




有區別


有區別


有空盒


mn




有區別


有區別


無空盒


M!s(n,m)




有區別


無區別


有空盒


S(n,1)+s(n,2)+…+s(n,m),n>=m
S(n,1)+s(n,2)+…+s(n,n),n<=m




有區別


無區別


無空盒


S(n,m)




無區別


有區別


有空盒


C(n+m-1,n)




無區別


有區別


無空盒


C(n-1,m-1)




無區別


無區別


有空盒


F(m,n)




無區別


無區別


無空盒


F(m,n-m)










然後,其中的F(m,n)貌似是當時寫過的一個DP,S(M,N)是第二類stirling數……遞推公式:1 int S(int n,int m) {2 if (n == m || m == 1) return 1;3 return m * S(n - 1, m) + S(n - 1, m - 1);4 }第一部分:可以看作這麼一個生成函數的相關問題:由於每個東西之間都隔了>=K-1的一段距離,因此一個可行解可以看作,長度爲K,K + 1,K + 2的棍子r - 1個(我們認爲每個棍子的頭是我們取的點),拼接成長度爲Len的一個大段,之後再堵上一個,就是一個Len +1的可行解……而r - 1根棍子,拼成長度爲Len 的可行解數目,就是(X^K + X^(K + 1) + X^(K + 2) + .....) ^ (r - 1),這個多項式,展開之後,X^Len項前面的係數……不過……由於數據範圍,直接搞是不成的……於是提取,變形:X^(K * (r - 1)) * (1 + X + X^2 + X ^3 +....)^(r - 1)然後再變形:X^(K * (r - 1)) * (1/(1 - x))^(r - 1)……然後參照Matrix67大神的日誌,展開後面那項:1/(1-x)^n=1+C(n,1)x^1+C(n+1,2)x^2+C(n+2,3)x^3+...+C(n+k-1,k)x^k+...我們知道,要求長度爲len的可行數目,也就是要X^Len項前面的係數,然後,由於前面提取出來了一個K * (r - 1),也就是去後面找len - K * (r - 1) 項的係數……也就是說,令pow = len - K * (r - 1),答案就是C(r - 1 + pow - 1, pow)……不過這還沒完,因爲咱們要拼成的長度是len,而總的長度是N,需要乘上這個長度len的開頭位置的可能數……另外還需要特殊處理:咱們在處理的時候,是先用r - 1個拼接成長度爲Len的一個大段,再堵上最後一個……當r == 1需要特判……代碼: 1 #include <cstdio> 2 #include <cstring> 3 4 typedef long long Long; 5 const Long MOD = 1000000007; 6 7 Long F[1010][1010]; 8 Long C[2010][2010]; 9 Long S(int n,int m) {10 if (n == m || m == 1) return 1LL;11 if (F[n][m] > 0) return F[n][m];12 return F[n][m] = (m * S(n - 1, m) % MOD + S(n - 1, m - 1)) % MOD;13 }14 void init() {15 for (int i = 0; i <= 2000; i++) {16 for (int j = 0; j <= i; j++) {17 if (j == 0) C[i][j] = 1;18 else C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MOD;19 }20 }21 }22 int n,r,k,m;23 24 int main() {25 memset(F,0xff,sizeof(F));26 init();27 while (scanf("%d%d%d%d",&n,&r,&k,&m) > 0) {28 if (r == 1) {printf("%d\n",n); continue;}29 Long ans = 0;30 for (int i = 1; i <= m && i <= r; i++) {31 ans = (ans + S(r,i)) % MOD;32 }33 Long tmp = 0;34 for (int len = k * (r - 1); len < n; len++) {35 int left = n - len;36 int pow = len - k * (r - 1);37 // r > 1 !!38 tmp = (tmp + left * C[r - 1 + pow - 1][pow]) % MOD;39 }40 ans = ans * tmp % MOD;41 printf("%lld\n",ans);42 }43 return 0;44 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章