P2577:「ZJOI2005」午餐题解

主要思路

容易想出状态\(dp[i][j][k]\)代表前\(i\)个人在一号队列排\(j\)分钟及在二号队排\(k\)分钟的最小时间。然后发现\(k\)这一维可以直接消去,因为有\(k=sum[i]-j\)。所以把线性依赖消去后,方程就非常小清新了:

\[dp[i][j] = min\{dp[i][j], max\{dp[i – 1][j – persons[i].a], j + persons[i].b\}\},当persons[i].a\leq j\]

\[dp[i][j] = min\{dp[i][j], max\{dp[i – 1][j], sum[i] – j + persons[i].b\}\}\]

代码

// P2577.cpp
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
using namespace std;
const int MX_N = 220;
struct person
{
    ll a, b;
    bool operator<(const person &ps) const
    {
        return b > ps.b;
    }
} persons[MX_N];
ll sum[MX_N], n, dp[MX_N][MX_N * MX_N];
int main()
{
    scanf("%lld", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld", &persons[i].a, &persons[i].b);
    sort(persons + 1, persons + 1 + n);
    for (int i = 1; i <= n; i++)
        sum[i] = sum[i - 1] + persons[i].a;
    memset(dp, 0x3f, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= sum[i]; j++)
        {
            if (j >= persons[i].a)
                dp[i][j] = min(dp[i][j], max(dp[i - 1][j - persons[i].a], (ll)(j + persons[i].b)));
            dp[i][j] = min(dp[i][j], max(dp[i - 1][j], sum[i] - j + persons[i].b));
        }
    ll ans = 0x7fffffff;
    for (int i = 0; i <= sum[n]; i++)
        ans = min(ans, dp[n][i]);
    printf("%lld", ans);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *