破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了破防了
$ T1 $
怎麼每次 $ rfy $ 模擬賽,$ T1 $ 都這麼難。
想了大半場比賽,結果還沒做出來,要是換成 $ T2 $ 應該能過。
$ T2 $
一直在想 $ T1 $,結果 $ T2 $ 只打了個暴力,$ T2 $ 相對 $ T1 $ 還是容易的。
設 $ f_{i, x, y} $ 表示前 $ i $ 個數,$ 1 $ 抽出 $ x $ 個,$ 2 $ 抽出 $ y $ 個的車數和最後一輛車的裝載量(是 $ pair $ 型別,甚至沒有看到 $ a_i = 1/2 $)。
然後轉移先不考慮抽出的裝載,只考慮在原序列中的裝載,抽出的到最後再計算。
則 $ f_{i, x, y} = min(f_{i - 1, x - 1, y}[x > 0], f_{i - 1, x, y - 1}[y > 0], f[i - 1][x][y] + a[i]) $, $ + a_i $ 可以過載運算子一下,$ x, y $ 的範圍用字首和預處理出前 $ i $ 個數中 $ 1/2 $ 的個數。
最後答案在 $ f[n][x][y] $ 統計即可。
注意到會 $ MLE $,所以需要開個滾動陣列最佳化一下空間。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define need(x) (bool)x.flow + x.cnt_car
#define sum(x) x.cnt_car * w + x.flow
using namespace std;
const int N = 410;
int n, w;
int a[N], sum1[N], sum2[N];
struct sb
{
int cnt_car, flow;
} f[2][N][N];
sb operator + (sb a, int b)
{
return {a.flow + b >= w ? a.cnt_car + 1 : a.cnt_car, a.flow + b == w ? 0 : a.flow + b > w ? b : a.flow + b};
}
sb mn(sb a, sb b)
{
return a.cnt_car >= inf ? b : b.cnt_car >= inf ? a : sum(a) > sum(b) ? b : a;
}
int main()
{
freopen("pack.in", "r", stdin);
freopen("pack.out", "w", stdout);
cin >> n >> w;
for (int i = 1; i <= n; i ++ ) cin >> a[i];
for (int i = 1; i <= n; i ++ )
sum1[i] = sum1[i - 1] + (a[i] == 1),
sum2[i] = sum2[i - 1] + (a[i] == 2);
// for (int i = 1; i <= n; i ++ ) cout << sum1[i] << ' ' << sum2[i] << '\n';
memset(f, 0x3f, sizeof f);
f[0][0][0] = {0, 0};
for (int i = 1; i <= n; i ++ )
{
for (int x = 0; x <= sum1[i]; x ++ )
for (int y = 0; y <= sum2[i]; y ++ )
{
f[i & 1][x][y] = {inf, inf};
if (x && a[i] == 1) f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x - 1][y]);
if (y && a[i] == 2) f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x][y - 1]);
f[i & 1][x][y] = mn(f[i & 1][x][y], f[(i - 1) & 1][x][y] + a[i]);
// cout << (f[(i - 1) & 1][x][y] + a[i]).cnt_car << '\n';
}
}
// cout << inf * 10 << '\n';
// for (int x = 0; x <= sum1[n]; x ++ )
// for (int y = 0; y <= sum2[n]; y ++ )
// cout << f[n & 1][x][y].cnt_car*w+f[n&1][x][y].flow << "\n"[y != sum2[n]];
int res = inf, mi = inf;
for (int x = 0; x <= sum1[n]; x ++ )
for (int y = 0; y <= sum2[n]; y ++ )
{
auto tmp = f[n & 1][x][y];
// cout << tmp.cnt_car << ' ' << tmp.flow << '\n';
int tx = x, ty = y;
while (tx || ty)
{
if (tx && (!ty || tmp.flow + 2 > w)) tx -- , tmp = tmp + 1;
else ty -- , tmp = tmp + 2;
}
// cout << tmp.cnt_car << ' ' << tmp.flow << '\n';
// cout << need(tmp) << '\n';
if (mi > need(tmp))
{
mi = need(tmp);
res = x + y;
}
else if (mi == need(tmp)) res = min(res, x + y);
}
cout << res << '\n';
return 0;
}
$ T3 $
$ T4 $