cf1348 F. Phoenix and Memory(贪心,二分)

https://codeforces.com/contest/1348/problem/F

题意:

是否存在唯一的一个 \(1\sim n\) 的排列 \(c[]\) ,满足 \(a_i \leq c_i \leq b_i\) ?

题目保证存在。若排列唯一,输出这个排列;若不唯一,输出两种可能的排列

思路:

首先找一个可行解。贪心,对 \(i=1\to n\),把 \(i\) 放在左端点小于等于 \(i\) 的区间中右端点最小的那一个。做法是先将所有区间按左端点从小到大排序,再用小根堆为每个 \(i\) 找到右端点最小的区间 \(home[i]\)

如果存在另外的解,那么一定能通过交换某两个数字 \(i\) 和 \(j\) 得到。能交换的条件是 \(home[j].a\le i<j\le home[i].b\)

从满足 \(home[j].a\le i\) 的数字 \(J\) 中找一个大于 \(i\) 的最小的数 \(j\),再判断这个数是否满足 \(j\le b\) 。如果 \(j>b\) ,那后面的数字比 \(j\) 还大,更不可能

#include <bits/stdc++.h>
using namespace std;
#define PRINT for(int z=1;z<=n;z++)cout<<ans[z]<<(z<n?' ':'\n')

const int N = 2e5+10;

struct Interval
{
    int a, b, id;
    bool operator> (Interval tmp) const
    {return b > tmp.b; }
} c[N];

vector<int> leftIs[N];
priority_queue<Interval, vector<Interval>, greater<Interval> > qu;
set<int> st;
int home[N], ans[N];

signed main()
{
    int n; cin >> n;
    for(int i = 1; i <= n; i++)
    {
        cin >> c[i].a >> c[i].b; c[i].id = i;
        leftIs[c[i].a].push_back(i);
    }

    for(int i = 1; i <= n; i++)
    {
        for(auto it : leftIs[i]) qu.push(c[it]);
        home[i] = qu.top().id;
        ans[qu.top().id] = i;
        qu.pop();
    }

    for(int i = 1; i <= n; i++)
    { //把左端点<=i的区间对应的数字加入set
        for(auto it : leftIs[i]) st.insert(ans[it]);
        auto it = st.upper_bound(i); int j = *it;
        if(it != st.end() && j <= c[home[i]].b)
        {
            puts("NO"); PRINT;
            swap(ans[home[i]], ans[home[j]]);
            PRINT; return 0;
        }
    }
    puts("YES"); PRINT;

    return 0;
}

上一篇:上手体验!如何借助龙蜥实验室快速部署 Web 应用?


下一篇:矩阵乘法cache优化