Canvas Line
链接 : https://codeforces.com/gym/102500/problem/C
题意 :
给出 n 个区间, m 个点, 要求加入最少的点使得每个区间中恰好包含 2 个点.
思路 :
贪心, 先处理给出的 m 个点, 标记它们的位置, 然后考虑加点的方式 :
1) 若该区间有 2 个点了, continue.
2) 若该区间正好 1 个点, 若能在其右端点加点(要保证该位置未被标记且下一个区间不会因为该操作点数超过 2), 必在其加点. 若右端点已被标记或不能在这加点, 则从右端点往后找一个可加的点加上.
3) 若该区间 0 个点, 必能在右端点 - 1 处加点, 右端点能加必加, 不能加则在 右端点 - 2 处加点.
代码 :
#include <bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
inline int lowbit(int x) { return x & (-x); }
#define ll long long
#define pb push_back
#define PII pair<int, int>
#define fi first
#define se second
#define inf 0x3f3f3f3f
const int N = 1e3 + 7;
unordered_map<int, int> st;
int a[2 * N];
struct node {
int l, r, cnt;
bool operator < (const node& t) const {
return l < t.l;
}
}p[N];
int main() {
IO;
int n, m, x;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> p[i].l >> p[i].r;
sort(p + 1, p + 1 + n);
cin >> m;
for (int i = 1; i <= m; ++i) {
cin >> a[i];
st[a[i]] = 1;
}
for (int i = 1, j = 1; i <= m; ++i) {
while (a[i] > p[j].r && j <= n) j++;
if (a[i] >= p[j].l) {
p[j].cnt++;
if (p[j].r == p[j + 1].l && a[i] == p[j].r) p[j + 1].cnt++;
}
}
for (int i = 1; i <= n; ++i)
if (p[i].cnt > 2) {
cout << "impossible\n";
return 0;
}
vector<int> ans;
for (int i = 1; i <= n; ++i) {
if (p[i].cnt == 1) {
if (st[p[i].r]) ans.pb(p[i].r - 1);
else {
if (p[i].r == p[i + 1].l && p[i + 1].cnt < 2) {
ans.pb(p[i].r);
p[i + 1].cnt++;
} else {
int pos = p[i].r - 1;
while (st[pos]) pos--;
ans.pb(pos);
}
}
} else if (p[i].cnt == 0) {
ans.pb(p[i].r - 1);
if (p[i].r == p[i + 1].l && p[i + 1].cnt < 2) {
ans.pb(p[i].r);
p[i + 1].cnt++;
} else ans.pb(p[i].r - 2);
}
}
cout << ans.size() << endl;
for (auto t : ans) cout << t << " ";
return 0;
}