Divine Gifting ( [2024-2025 ICPC Southwestern European Regional Contest (SWERC 2024)](gym105677). )

Divine Gifting ( 2024-2025 ICPC Southwestern European Regional Contest (SWERC 2024). )

A celestial scroll, detailing Zeus’s latest whim unfurls before Hermes: the next few millenia will be a period of divine gifting for mortals. Hermes, the messenger god, is tasked with delivering these gifts. Not just any gifts, mind you, but exquisitely crafted items from the Olympian workshops: a lyre that plays melodies of pure joy, a quill that writes words of profound wisdom, and so on. Each of the N N N gifts is unique, and, to complicate matters, each has an optimal delivery date, a day when its magic would be most potent. But a divine law forbids delivering gifts before their optimal delivery day, lest mortals become complacent and entitled. Of course, all gifts must be delivered.

Adding to the challenge, Hermes, despite being the fastest god on Olympus, is always extremely busy. Between managing the celestial postal service and refereeing chariot races, he knows that he can only dedicate at most K K K days for the deliveries (each of those days, Hermes can deliver any number of gifts). Furthermore, late deliveries incur penalties: for each gift, the penalty is the square of the difference between its actual delivery day and its optimal delivery day. If a lyre is delivered a day or two late, a village might experience a few hours of slightly off-key music. A minor inconvenience, to be sure. However, if the lyre is delivered a month or a year late, the consequences are far more dire: a full year of discordant melodies, enough to drive even the most stoic musician to madness. The potential for chaos is immense.

And this is where you come in, mortal friend. Hermes, with his myriad responsibilities, could use a helping hand. Can you help him plan his divine calendar by determining the best days for delivering the gifts, so as to minimize the sum of late delivery penalties?

Input

On the first line of the input, two space-separated integers:

  • N N N, the number of gifts;
  • K K K, the maximum number of days Hermes dedicates to gifting.

On the second line, N N N space-separated integers d i d_{i} di, representing the optimal delivery date of each gift.

Output

A single line of space-separated integers, where the i i i-th element is the day when Hermes should deliver the i i i-th gift. If there are multiple optimal solutions, they will all be accepted.

Limits

  • 1 ≤ N ≤ 5 , 000 1 \leq N \leq 5,000 1N5,000
  • 1 ≤ K ≤ 20 1 \leq K \leq 20 1K20
  • 0 ≤ d i ≤ 1 , 000 , 000 0 \leq d_i \leq 1,000,000 0di1,000,000 for all i ≤ N i \leq N iN

Example

Input

5 2
50 0 51 10 50

Output

51 10 51 10 51 

题目大意

宙斯决定在接下来的几千年里为凡人分发礼物。赫尔墨斯(Hermes)被指派负责分发这些礼物。每个礼物都有一个最佳的交付日期,且不能在最佳日期之前交付。赫尔墨斯最多只能使用 K K K 天来分发所有礼物。如果礼物在最佳日期之后交付,会产生惩罚,惩罚值为实际交付日期与最佳交付日期之差的平方。目标是找到一种分发礼物的方案,使得总惩罚最小。

题解

  1. 问题分析:

    • 每个礼物有一个最佳交付日期 d i d_i di,且不能在 d i d_i di 之前交付。
    • 赫尔墨斯最多只能使用 K K K 天来分发所有礼物。
    • 目标是找到一种分发方案,使得总惩罚最小。
  2. 关键思路:

    • 首先将所有礼物按照最佳交付日期排序。
    • 使用动态规划(DP)来计算最小惩罚。定义 d p [ i ] [ k ] dp[i][k] dp[i][k] 表示前 i i i 个礼物使用 k k k 天分发的最小惩罚。
    • 通过枚举前 j j j 个礼物使用 k − 1 k-1 k1 天分发,剩下的 j + 1 j+1 j+1 i i i 个礼物在第 k k k 天分发,来更新 d p [ i ] [ k ] dp[i][k] dp[i][k]
  3. 复杂度:

    • 时间复杂度为 O ( N 2 × K ) O(N^2 \times K) O(N2×K),其中 N N N 是礼物的数量, K K K 是最大分发天数。

代码分析

  1. 输入处理:

    • 读取礼物的数量 N N N 和最大分发天数 K K K
    • 读取每个礼物的最佳交付日期 d i d_i di,并排序。
  2. 预处理:

    • 计算 s u m [ l ] [ r ] sum[l][r] sum[l][r],表示从第 l l l 个礼物到第 r r r 个礼物在第 k k k 天分发的总惩罚。
  3. 动态规划:

    • 初始化 d p [ 0 ] [ 0 ] = 0 dp[0][0] = 0 dp[0][0]=0
    • 对于每个礼物 i i i,枚举前 j j j 个礼物使用 k − 1 k-1 k1 天分发,剩下的 j + 1 j+1 j+1 i i i 个礼物在第 k k k 天分发,更新 d p [ i ] [ k ] dp[i][k] dp[i][k]
  4. 回溯:

    • 通过回溯找到最优的分发方案。
    • 根据最优方案,输出每个礼物的实际交付日期。

代码实现

#include 
using namespace std;
#define int long long int
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 5000 + 10;
const int inf = 1e18;
vector<vector<int>> dp(N, vector<int>(25, inf));
int n, K;
vector<int> v(N);

int cmp(int x, int y)
{
    return x > y;
}

int sum[N][N];

void dodo()
{
    for (int r = n; r >= 1; --r)
    {
        for (int l = r; l >= 1; --l)
        {
            sum[l][r] = sum[l + 1][r] + abs((v[r] - v[l]) * (v[r] - v[l]));
        }
    }
}

signed main()
{
    close;

    cin >> n >> K;
    // K = min(K, n);
    for (int i = 1; i <= n; ++i)
    {
        cin >> v[i];
    }
    vector<pair<int, int>> s(n + 1);
    for (int i = 1; i <= n; i++)
        s[i].first = v[i], s[i].second = i;
    sort(s.begin() + 1, s.begin() + 1 + n);
    sort(v.begin() + 1, v.begin() + n + 1);
    dodo();

    // for (int r = n; r >= 1; --r)
    // {
    //     for (int l = r; l >= 1; --l)
    //     {
    //         cout << l << ' ' << r << ' ' << sum[l][r] << endl;
    //     }
    // }

    dp[0][0] = 0;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0; j < i; ++j)
        {
            for (int k = K; k >= 1; --k)
            {
                dp[i][k] = min(dp[i][k], dp[j][k - 1] + sum[j + 1][i]);
            }
        }
    }
    // cout << dp[n][K];

    // for (int i = 1; i <= n; ++i)
    // {
    //     for (int j = 1; j <= K; ++j)
    //     {
    //         cout << dp[i][j] << ' ';
    //     }
    //     cout << endl;
    // }

    vector<int> an;
    an.push_back(n);
    array<int, 3> now;
    now = {n, min(n, K), dp[n][min(n, K)]};
    for (int i = K; i >= 1; i--)
    {
        for (int j = 1; j <= now[0]; j++)
        {
            if (now[2] - dp[j][i - 1] == sum[j + 1][now[0]])
            {
                now[0] = j, now[1]--, now[2] = dp[j][i-1];
                an.push_back(j);
                break;
            }
        }
    }
    reverse(an.begin(), an.end());
    // for (auto it : an)
    // {
    //     cerr << it << ' ';
    // }
    //cout << endl;
    int no = 0;
    vector<int> ans(n + 10);
    for (int i = 1; i <= n; i++)
    {
        if (i <= an[no])
            ans[s[i].second] = v[an[no]];
        if (i == an[no])
            no++;
    }
    for (int i = 1; i <= n; i++)
        cout << ans[i] << " ";
    cout << endl;
}

总结

这道题目通过动态规划的方法,解决了在有限天数内分发礼物并最小化惩罚的问题。关键在于如何定义状态转移方程,并通过预处理来优化计算。最终的代码实现了这一思路,并通过回溯找到最优的分发方案。

你可能感兴趣的:(acm训练集合,dp,逆推,线性dp)