• 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 << '
    ';
     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 << '
    ';
     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 << '
    ';
     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) << '
    ';
    100     double E = ans.first / ans.second;
    101     printf("%.9lf", E);
    102 }
    103 
    104 int main() {
    105     init();
    106     solve();
    107     return 0;
    108 }
  • 相关阅读:
    洛谷P1258小车问题
    洛谷P1028 数的计算
    P1980 计数问题
    洛谷P1907口算练习题
    2018icpc沈阳-K.Let the Flames Begin (约瑟夫环问题)
    Codeforces Round #585 (Div. 2) B. The Number of Products
    字符串部分模板总结
    CF-1209D Cow and Snacks (并查集,图)
    Codeforces Round #584 (div.1+div.2)(补题)
    HDU
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9895735.html
Copyright © 2020-2023  润新知