div3E. Beautiful Array

E. Beautiful Array

原题链接

题目

思路

题目数组可以任意排序,简化为数组每个数两两配对(奇数就多一个不用管),配对就是两个数差是k的倍数 abs(nums-num2)%k==0
我们把所有模k相等的数分为一类,因为这样的数互相可配对
这样就得到了k个数组,每个数组长度如果是奇数就会多一个数无法匹配,所有数组在一起我们最多可接受一个多出来的数,超过就直接输出-1即可。
对于每个数组求独立转化成美丽数组的最小操作数最后相加就是答案
这个时候问题转换成了一个同模数组求最小操作数(操作就是选择一个数使它加k)使数字两两相等(奇数数量就多一个。
重点:
问题抽象成一个数轴上一系列点如何两两连线配对使线最短

  • 偶数数量
    显然连接1 2 4 5 最短,容易看出相邻两个连接是最优解法
  • 奇数数量
    枚举那个多余的点,两边就变成了偶数的情况
    枚举过程使用前缀和(左右)处理左右偶数情况的操作数即可
    前缀和
    xiwen_Java糕手
    我的代码是用dp包括了奇数和偶数的情况dp[i][0]表示下标<=i的子情况num[i]不是剩下的操作数,dp[i][1]是下标<=i的子情况num[i]是剩下的操作数。
    dp[0][1]=0一个数刚刚好剩下操作数就是0
    dp[0][0]一个数还不剩下显然不合法情况设置成INT_MAX
    当i是奇数时候由于是下标从0开始,此时数量位偶dp[i][0] = min(dp[i - 2][0], dp[i - 1][1]) + 新增操作数;此时dp[i][1]不合法不用管
    当i是偶数时候,这时候个数是奇数,dp[i][1] = dp[i - 1][0];dp[i][0] = min(dp[i - 2][0], dp[i - 2][1]) + t;
    最终ans += (len & 1) ? min(dp[len - 1][1], dp[len - 1][0]) : dp[len - 1][0];

代码

// https://codeforces.com/contest/1986/problem/E
#include <bits/stdc++.h>
#define caseT \
    int T;    \
    cin >> T; \
    while (T--)
using namespace std;
using ll = long long;
void solve() {
    ll n, k, ans = 0, num2 = 0;
    cin >> n >> k;
    vector<ll> nums(n);
    for (int i = 0; i < n; i++) cin >> nums[i];
    sort(nums.begin(), nums.end());
    map<ll, vector<ll>> H;
    for (ll num : nums) H[num % k].push_back(num);
    for (auto &[key, p] : H) {
        if (p.size() & 1 && ++num2 >= 2) {
            cout << "-1" << endl;
            return;
        }
        int len = p.size();
        vector<vector<ll>> dp(len, vector<ll>(2));
        dp[0][0] = INT_MAX;
        if (len > 1) dp[1] = {(p[1] - p[0]) / k, INT_MAX};
        for (int i = 2; i < len; i++) {
            ll t = (p[i] - p[i - 1]) / k;
            if (i & 1) {
                dp[i][0] = min(dp[i - 2][0], dp[i - 1][1]) + t;
            } else {
                dp[i][1] = dp[i - 1][0];
                dp[i][0] = min(dp[i - 2][0], dp[i - 2][1]) + t;
            }
        }
        ans += (len & 1) ? min(dp[len - 1][1], dp[len - 1][0]) : dp[len - 1][0];
    }
    cout << ans << endl;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    caseT solve();
    return 0;
}
posted @ 2024-07-10 11:46  yuzhongrun  阅读(33)  评论(0编辑  收藏  举报