题目传送门ios
传送门优化
题目大意spa
餐厅有$n$张桌子,第$i$张桌子能够容纳$c_i$我的,有$t$组客人,每组客人的人数等几率是$[1, g]$中的整数。code
每来一组人数为$x$客人,餐厅若是能找到最小的$c_j$使得$c_j \geqslant x$,那么就会把这张桌子分配给这些客人,并获得$x$的收益。blog
问指望的收益。排序
好像能够枚举每一种人数,而后算一下,但时间复杂度很爆炸。get
先添加若干个容量为$\infty$的桌子。这样每组人必定可以分配到一张桌子,只是可能没有收益。it
考虑最后答案必定是将桌子排序后,若干段连续的桌子被占用。io
用$f_{l, r}$表示刚好$[l, r]$这段桌子被占用的全部方案的收益总和和方案数。每次转移考虑枚举最后一组人来的时候占用的桌子,假如它是$mid$,那么最后一组人可行的人数是$(c_{l - 1}, c_{mid}]$。class
而后作一个背包,$h_{i, j}$表示考虑到在时刻$i$及其以后来的人,被占用的最靠左的左端点是$j$,全部方案的收益总和和方案数。转移的时候枚举这一段的长度,以及前一段的区间的左端点,注意两个区间不能相交。后者用一个后缀和优化掉。
注意每组人是带标号的,因此合并两个方案的时候还须要分配标号。
1 /** 2 * Codeforces 3 * 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 long double 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 }