Codeforces Gym 101623E English Restaurant - 动态规划

题目传送门

  传送门

题目大意

  餐厅有$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  * 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 }
posted @ 2018-11-02 13:23  阿波罗2003  阅读(262)  评论(0编辑  收藏  举报