题解「SWTR-6」Snow Mountain

「SWTR-6」Snow Mountain

假设我们已经构造出一种方案摧毁了所有的水晶,要求最小的花费,显然是一个经典的贪心问题,直接从大到小选即可。

那么问题就在与我们要如何构造出一个满足条件的方案并让它的花费最小,题目中保证了 \(n\) 为偶数,并且 \(a_{x_i}>a_i\),不妨将这个数列升序排列,令前半段为 \([a_1,...,a_{mid}]\),后半段为 \([a_{mid+1},...,a_n]\) (这里的 \(a_i\) 表示水晶的编号),显然,如果能够让前半段的所有数与后半段匹配,那么花费一定能够最小,并且在排完序过后,我们不用考虑后半段是否会与前半段共振,只需要考虑前半段即可。

这里给出一种配对的方法,用一个双端队列将后半段存下来,每一次匹配都与队头或队尾中不与 \(a_i\) 号水晶共振的匹配,能够证明,这种方法至少能够匹配 \(\frac{n}{2}-1\) 对水晶,并且剩下的一定是 \(a_{mid}\),设后半段剩下的水晶为 \(a_x\),这时候我们可以这样处理,找到之前已经匹配的水晶,看一下能否交换,如果还不行,那么就说明前半段不能全部都和后半段匹配。

这时候考虑另外一种方案,让前半段与后半段的一个水晶分别来与剩下的匹配,所以我们需要找出一对已经匹配的水晶将它们拆开来分别与剩下的匹配,注意在找的时候如果有在右半段的水晶的能量值更小的匹配满足条件,就用更小的,如果一对都找不出来,那么就说明一定无解。

至此,我们就已经构造出了一个合法的方案,注意在输出的时也要按贪心时选择的顺序输出,因为这个WA了好多次

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#define ax first
#define ay second
#define mk make_pair
using namespace std;
const int N = 5e5 + 5;
typedef pair<int, int> PII;

struct node
{
    int a, x, id;
    bool operator < (const node t) const
    {
        return a < t.a;
    }
} p[N];
int x[N], a[N];
vector<PII> ans;

bool cmp(PII x, PII y)
{
    return min(a[x.ax], a[x.ay]) > min(a[y.ax], a[y.ay]);
}

int main()
{
    int n;
    scanf("%d", &n);
    int tot = n;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &p[i].a);
        p[i].id = i, a[i] = p[i].a;
    }
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &p[i].x);
        if (p[i].x == -1)
            p[i].x = ++tot;
        x[i] = p[i].x;
    }
    int len = n >> 1;
    sort(p + 1, p + 1 + n);
    int l = len + 1, r = n;
    for (int i = 1; i <= len; i++)
    {
        if (p[i].x != p[r].id)
            ans.push_back(mk(p[i].id, p[r--].id));
        else if (p[i].x == p[r].id && p[i].x != p[l].id)
            ans.push_back(mk(p[i].id, p[l++].id));
    }
    if (ans.size() != len)
    {
        for (int i = 0; i < len - 1; i++)
        {
            if (x[ans[i].ax] != p[l].id && p[len].x != ans[i].ay)
            {
                ans.push_back(mk(ans[i].ax, p[l].id)), ans[i].ax = p[len].id;
                break;
            }        
        }
    }
    if (ans.size() != len)
    {
        int rec = -1;
        for (int i = 0; i < len - 1; i++)
        {  
            if (x[ans[i].ax] != p[len].id && x[ans[i].ay] != p[l].id && p[l].x != ans[i].ay)
                if (rec == -1 || ans[i].ay < ans[rec].ay)
                    rec = i; 
        }
        if (rec != -1)
        {
            ans.push_back(mk(ans[rec].ax, p[len].id));
            ans[rec].ax = ans[rec].ay, ans[rec].ay = p[l].id;            
        }
    }
    if (ans.size() != len)
        puts("-1");
    else
    {
        sort(ans.begin(), ans.end(), cmp);
        long long sum = 0;
        for (long long i = 0; i < len; i++)
            sum += min(a[ans[i].ax], a[ans[i].ay]) * (i + 1);
        printf("%lld\n", sum);
        for (int i = 0; i < len; i++)
            printf("%d %d\n", ans[i].ax, ans[i].ay);
    }
    return 0;
}
```题解「SWTR-6」Snow Mountain
posted @ 2021-08-28 08:27  DSHUAIB  阅读(47)  评论(0编辑  收藏  举报