ABC382 C-F题解
C - Kaiten Sushi
把寿司都放到一个堆里,从前往后扫 \(A\) 数组,如果当前食客 \(A_i\) 小于等于堆顶,就取出堆顶,记录这份寿司被第 \(i\) 个人吃掉。复杂度 \(O(n\log m)\)。
D - Keep Distance
搜索回溯,但每一步从 \(10\) 枚举到 \(m\) 会超时,剪一下枝 for (int i = 10; res.back() + i <= m - 10 * (n - siz - 1); i++)。
E - Expansion Packs
设 \(f_i\) 表示再拿 \(i\) 个稀有卡期望 \(f_i\) 步,发现 \(f_i=1+f_ig_0+f_{i-1}g_1+f{i-2}g_2+\cdots\)。把 \(f_ig_0\) 移到等式左边,有 \((1-g_0)f_i=1+\sum\limits_{j=1}^i f_{i-j}g_j\),其中 \(g_j\) 表示从一个袋子里拿到 \(j\) 个稀有卡的概率。得到 dp 方程 \(f_i=\dfrac{1+\sum\limits_{j=1}^i f_{i-j}g_j}{1-g_0}\)。
\(g\) 数组可以通过 \(O(n^2)\) 的 dp 求出。设 \(dp_{i,j}\) 表示一个袋子里前 \(i\) 张卡中有 \(j\) 个稀有卡的概率,于是有 \(dp_{i,j}=dp_{i-1,j-1}p_i+dp_{i-1,j}(1-p_i)\),注意 \(j=0\) 时的边界情况。\(dp_{n,j}\) 即为 \(g_j\)。
void solve() {
using f128 = long double;
int n, x;
cin >> n >> x;
vector<f128> p(n + 1);
for (int i = 1; i <= n; i++) {
cin >> p[i];
p[i] /= 100;
}
vector dp(n + 1, vector<f128>(n + 1));
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j <= i; j++) {
dp[i][j] = dp[i - 1][j] * (1 - p[i]);
if (j) dp[i][j] += dp[i - 1][j - 1] * p[i];
}
}
vector<f128> f(x + 1, 1);
vector<f128>& g = dp[n];
f[0] = 0;
for (int i = 1; i <= x; i++) {
for (int j = 1; j <= min(n, i); j++)
f[i] += f[i - j] * g[j];
f[i] /= (1 - g[0]);
}
cout << fixed << setprecision(16) << f[x] << '\n';
}
F - Falling Stars
把横线从下到上排序,开一棵线段树记录每个位置摞了多少层。要加入一条横线的时候,先查询对应区间 \([C_i,C_i+L_i-1]\) 的最小值(最高层数)\(r\),则该横线的层数就是 \(r-1\),区间赋值 \(r-1\) 即可。AC代码

浙公网安备 33010602011771号