题目:中文
思路上这题不难想到:首先从左边扫一遍位置,记录每个空位置左边连续的空位置,然后再从右扫一遍,记录每个空位置右边的连续空位置.(注意把这些空位置放入set中去).
然后把set内的首元素拿出来就是满足条件的一个座位。然后把这个座位标记为坐上,在set中删掉,更新以这个位置为分界的左边的椅子和右边的椅子,重复操作。
比较难想到的是用set自带的排序来做,开始我用优先队列来做,发现删除有点困难,如果做上标志的话复杂度应该也会很高。
#include <bits/stdc++.h>
using namespace std;
int a[100005];
typedef pair <int, pair<int, int> > P;
int l[100005], r[100005];
set < P > SET;
int main()
{
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
memset(a, 0, sizeof(a));
for(int i = 1, x; i <= m; i++) {
scanf("%d", &x);
a[x] = 1;
}
int lnum = 0;
for(int i = 1; i <= n; i++) {
if(a[i]) lnum = 0;
else {
l[i] = lnum++;
}
}
int rnum = 0;
for(int i = n; i >= 1; i--) {
if(a[i]) rnum = 0;
else {
r[i] = rnum++;
}
}
for(int i = 1; i <= n; i++) {
if(!a[i]) {
SET.insert(make_pair(min(l[i], r[i]), make_pair(max(l[i], r[i]), -i)));///set对pair的排序是先按键值从小到大排,编号尽量小,所以给它加上符号来排序
}
}
while(k--) {
set<P>::reverse_iterator pos=SET.rbegin();
int id = -(*pos).second.second;
SET.erase(*pos);
printf("%d\n", id);
int rnum = 0;
a[id] = 1;
for(int i = id - 1; i >= 1; i--) {
if(a[i]) break;
else {
SET.erase(make_pair(min(l[i], r[i]), make_pair(max(l[i], r[i]), -i)));
r[i] = rnum++;
SET.insert(make_pair(min(l[i], r[i]), make_pair(max(l[i], r[i]), -i)));
}
}
int lnum = 0;
for(int i = id + 1; i <= n; i++) {
if(a[i]) break;
else {
SET.erase(make_pair(min(l[i], r[i]), make_pair(max(l[i], r[i]), -i)));
l[i] = lnum++;
SET.insert(make_pair(min(l[i], r[i]), make_pair(max(l[i], r[i]), -i)));
}
}
}
return 0;
}