Codeforces 101623E English Restaurant - 動態規劃
阿新 • • 發佈:2018-11-02
題目傳送門
題目大意
餐廳有$n$張桌子,第$i$張桌子可以容納$c_i$個人,有$t$組客人,每組客人的人數等概率是$[1, g]$中的整數。
每來一組人數為$x$客人,餐廳如果能找到最小的$c_j$使得$c_j \geqslant x$,那麼就會把這張桌子分配給這些客人,並得到$x$的收益。
問期望的收益。
好像可以列舉每一種人數,然後算一下,但時間複雜度很爆炸。
先新增若干個容量為$\infty$的桌子。這樣每組人一定能夠分配到一張桌子,只是可能沒有收益。
考慮最後答案一定是將桌子排序後,若干段連續的桌子被佔用。
用$f_{l, r}$表示恰好$[l, r]$這段桌子被佔用的所有方案的收益總和和方案數。每次轉移考慮列舉最後一組人來的時候佔用的桌子,假如它是$mid$,那麼最後一組人可行的人數是$(c_{l - 1}, c_{mid}]$。
然後做一個揹包,$h_{i, j}$表示考慮到在時刻$i$及其之後來的人,被佔用的最靠左的左端點是$j$,所有方案的收益總和和方案數。轉移的時候列舉這一段的長度,以及前一段的區間的左端點,注意兩個區間不能相交。後者用一個字尾和優化掉。
注意每組人是帶標號的,所以合併兩個方案的時候還需要分配標號。
Code
1 /** 2 * Codeforces3 * Gym#101623E 4 * Accepted 5 * Time: 46ms 6 * Memory: 2600k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cstdlib> 11 #include <cstdio> 12 #include <vector> 13 using namespace std; 14 typedef bool boolean; 15 16 typedef longdouble ld; 17 typedef pair<ld, ld> pdd; 18 19 pdd operator + (const pdd& a, const pdd& b) { 20 return pdd(a.first + b.first, a.second + b.second); 21 } 22 23 pdd operator * (const pdd& a, const pdd& b) { 24 return pdd(a.first * b.second + a.second * b.first, a.second * b.second); 25 } 26 27 pdd operator * (const pdd& a, ld x) { 28 return pdd(a.first * x, a.second * x); 29 } 30 31 ld nature_sum(int x) { 32 return x * (x + 1) >> 1; 33 } 34 35 const int N = 105; 36 37 int n, g, t; 38 vector<int> c; 39 ld C[N << 1][N << 1]; 40 pdd f[N << 1][N << 1], h[N][N << 1], s[N][N << 1]; 41 42 inline void init() { 43 scanf("%d%d%d", &n, &g, &t); 44 c.resize(n); 45 for (int i = 0; i < n; i++) { 46 scanf("%d", &c[i]); 47 c[i] = min(c[i], g); 48 } 49 for (int i = 0; i < t; i++) 50 c.push_back(g + 1); 51 sort(c.begin(), c.end()); 52 n = c.size(); 53 } 54 55 inline void solve() { 56 C[0][0] = 1; 57 for (int i = 1; i <= n; i++) { 58 C[i][0] = C[i][i] = 1; 59 for (int j = 1; j < i; j++) 60 C[i][j] = C[i - 1][j] + C[i - 1][j - 1]; 61 } 62 63 for (int r = 0; r < n; r++) 64 for (int l = r; ~l; l--) { 65 for (int mid = l; mid <= r; mid++) { 66 pdd val; //(0, 1);//C[r - l][r - mid]); 67 if (c[mid] > g) 68 val = pdd(0, g - ((l) ? (min(c[l - 1], g)) : (0))); 69 else 70 val = pdd(nature_sum(c[mid]) - ((l) ? (nature_sum(c[l - 1])) : (0)), c[mid] - ((l) ? (c[l - 1]) : (0))); 71 pdd vall = (mid > l) ? (f[l][mid - 1] * C[r - l][r - mid]) : (pdd(0, 1)); 72 pdd valr = (mid < r) ? (f[mid + 1][r]) : (pdd(0, 1)); 73 f[l][r] = f[l][r] + (vall * val * valr); 74 } 75 // cerr << l << " " << r << " " << f[l][r].first << " " << f[l][r].second << '\n'; 76 } 77 78 for (int i = 0; i < t; i++) 79 for (int j = 0; j < n - t + i + 1; j++) 80 h[i][j] = f[j][j + t - i - 1]; 81 for (int i = t; i--; ) { 82 int all = t - i; 83 for (int j = 0; j + all < n; j++) { 84 for (int k = i + 1; k < t; k++) { 85 int put = k - i; 86 // cerr << i << " " << j << " " << k << " " << all << " " << put << '\n'; 87 ld comb = C[all][put]; 88 h[i][j] = h[i][j] + (f[j][j + put - 1] * comb * s[k][j + put + 1]); 89 } 90 // cerr << i << " " << j << " " << h[i][j].first << " " << h[i][j].second << '\n'; 91 } 92 s[i][n - 1] = h[i][n - 1]; 93 for (int j = n - 2; j >= 0; j--) 94 s[i][j] = s[i][j + 1] + h[i][j]; 95 } 96 pdd ans(0, 0); 97 for (int i = 0; i < n; i++) 98 ans = ans + h[0][i]; 99 // cout << (ans.first / ans.second) << '\n'; 100 double E = ans.first / ans.second; 101 printf("%.9lf", E); 102 } 103 104 int main() { 105 init(); 106 solve(); 107 return 0; 108 }