Codeforces 101623E English Restaurant - 動態規劃

題目傳送門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$,全部方案的收益總和和方案數。轉移的時候枚舉這一段的長度,以及前一段的區間的左端點,注意兩個區間不能相交。後者用一個後綴和優化掉。

  注意每組人是帶標號的,因此合併兩個方案的時候還須要分配標號。

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 }
相關文章
相關標籤/搜索