ALGO-40 会议中心
资源限制
时间限制:2.0s 内存限制:512.0MB
问题描述
会议中心 Siruseri政府建造了一座新的会议中心。许多公司对租借会议中心的会堂很感兴趣,他们希望能够在里面举行会议。
对于一个客户而言,仅当在开会时能够独自占用整个会堂,他才会租借会堂。会议中心的销售主管认为:最好的策略应该是将会堂租借给尽可能多的客户。显然,有可能存在不止一种满足要求的策略。
例如下面的例子。总共有4个公司。他们对租借会堂发出了请求,并提出了他们所需占用会堂的起止日期(如下表所示)。
开始日期 | 结束日期 | |
---|---|---|
公司1 | 4 | 9 |
公司2 | 9 | 11 |
公司3 | 13 | 19 |
公司4 | 10 | 17 |
上例中,最多将会堂租借给两家公司。租借策略分别是租给公司1和公司3,或是公司2和公司3,也可以是公司1和公司4。注意会议中心一天最多租借给一个公司,所以公司1和公司2不能同时租借会议中心,因为他们在第九天重合了。
销售主管为了公平起见,决定按照如下的程序来确定选择何种租借策略:首先,将租借给客户数量最多的策略作为候选,将所有的公司按照他们发出请求的顺序编号。对于候选策略,将策略中的每家公司的编号按升序排列。最后,选出其中字典序最小[1]的候选策略作为最终的策略。
例中,会堂最终将被租借给公司1和公司3:3个候选策略是{(1,3),(2,3),(1,4)}。而在字典序中(1,3)<(1,4)<(2,3)。
你的任务是帮助销售主管确定应该将会堂租借给哪些公司。
输入格式
输入的第一行有一个整数N,表示发出租借会堂申请的公司的个数。第2到第N+1行每行有2个整数。第i+1行的整数表示第i家公司申请租借的起始和终止日期。对于每个公司的申请,起始日期为不小于1的整数,终止日期为不大于109的整数。
输出格式
输出的第一行应有一个整数M,表示最多可以租借给多少家公司。第二行应列出M个数,表示最终将会堂租借给哪些公司。
测试样例
输入:
4
4 9
9 11
13 19
10 17
输出:
2
1 3
数据规模与约定
对于50%的输入,N≤3000。在所有输入中,N≤200000。
AC code:
import java.io.*;
import java.util.*;
public class Main {
static int f[][], cases = 1;
static Node[] cas;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, " \n");
PrintWriter out = new PrintWriter(System.out);
int n = in.nextInt() + 1;
f = new int[n][21];
cas = new Node[n + 1];
Node[] arr = new Node[n];
for (int i = 1; i < n; i++) arr[i] = cas[i] = new Node(i, in.nextInt(), in.nextInt());
Arrays.sort(cas, 1, n);
for (int i = 1; i < n; i++) if (cas[cases].begin < cas[i].begin) cas[++cases] = cas[i];
cas[cases + 1] = new Node(0, Integer.MAX_VALUE, 0);
for (int i = 1, j = 1; i <= cases; j = ++i) {
while (cas[j].begin <= cas[i].end) j++;
if (j <= cases) f[i][0] = j;
}
for (int j = 1; j <= 20; j++)
for (int i = 1; i <= cases; i++) f[i][j] = f[f[i][j - 1]][j - 1];
out.println(calcCnt(0, Integer.MAX_VALUE));
Tree<Node> tree = new Tree(new Node(0), new Node(1000000000));
for (int i = 1; i < n; i++) {
Comparable[] cont = tree.search(arr[i]);
int l = ((Node)cont[0]).end, r = ((Node)cont[1]).begin;
if (l >= arr[i].begin || r <= arr[i].end) continue;
if (calcCnt(l + 1, r - 1) == calcCnt(l + 1, arr[i].begin - 1) + calcCnt(arr[i].end + 1, r - 1) + 1) {
tree.insert(arr[i]);
out.print(i + " ");
}
}
out.close();
}
static int calcCnt(int begin, int end) {
int res = 1, now = search(begin);
if (now > cases || cas[now].end > end) return 0;
for (int i = 20; i >= 0; i--)
if (f[now][i] > 0 && cas[f[now][i]].end <= end) {
now = f[now][i];
res += 1 << i;
}
return res;
}
static int search(int begin) {
int left = 1, right = cases;
while (left <= right) {
int mid = (right - left) / 2 + left;
if (cas[mid].begin > begin) right = mid - 1;
else if (cas[mid].begin < begin) left = mid + 1;
else return mid;
}
return right + 1;
}
static class Node implements Comparable<Node> {
int begin;
int end;
int id;
Node(int feel) {this.id = this.end = this.begin = feel;}
Node(int id, int begin, int end) {
this.id = id;
this.end = end;
this.begin = begin;
}
public int compareTo(Node t) { return this.end == t.end? t.begin - this.begin: this.end - t.end; }
}
static class Tree<T extends Comparable<T>> {
final boolean RED = true;
final boolean BLACK = false;
Node root;
class Node {
T value;
Node left;
Node right;
boolean color;
Node(T value, boolean color) {
this.value = value;
this.color = color;
}
}
Tree(T MINValue, T MAXValue) {
root = new Node(MAXValue, BLACK);
root.left = new Node(MINValue, RED);
}
void insert(T value) {
root = insert(root, value);
root.color = BLACK;
}
Comparable[] search(T node) {
Comparable[] res = new Comparable[2];
search(root, node, res);
return res;
}
void search(Node root, T node, Comparable[] res) {
if (root.value.compareTo(node) > 0) {
res[1] = root.value;
if (root.left != null) search(root.left, node, res);
} else {
res[0] = root.value;
if (root.right != null) search(root.right, node, res);
}
}
Node insert(Node root, T value) {
if (root == null) return new Node(value, RED);
if (root.value.compareTo(value) > 0) root.left = insert(root.left, value);
else root.right = insert(root.right, value);
if (isRed(root.right) && !isRed(root.left)) root = rotateLeft(root);
if (isRed(root.left) && isRed(root.left.left)) root = rotateRight(root);
if (isRed(root.left) && isRed(root.right)) flipColor(root);
return root;
}
boolean isRed(Node x) {
if (x == null) return false;
return x.color;
}
void flipColor(Node h) {
h.color = RED;
h.left.color = BLACK;
h.right.color = BLACK;
}
Node rotateLeft(Node h) {
Node x = h.right;
h.right = x.left;
x.left = h;
x.color = h.color;
h.color = RED;
return x;
}
Node rotateRight(Node h) {
Node x = h.left;
h.left = x.right;
x.right = h;
x.color = h.color;
h.color = RED;
return x;
}
}
static class InputReader {
BufferedReader read;
StringTokenizer token;
String delimiters;
InputReader(InputStream in) { this(in, " \t\n\r\f"); }
InputReader(InputStream in, String delimiters) {
this.read = new BufferedReader(new InputStreamReader(in));
this.token = new StringTokenizer("", this.delimiters = delimiters);
}
String next() {
while (!token.hasMoreTokens())
try {
this.token = new StringTokenizer(read.readLine(), delimiters);
} catch (IOException e) {
e.printStackTrace();
}
return token.nextToken();
}
int nextInt() { return Integer.parseInt(next()); }
}
}
参考
人写麻了
人看麻了,APIO的题跟蓝桥自己的题根本就不是一个层次的
先按自己的理解跑一遍:
import java.io.*;
import java.util.*;
public class Main {
static int[] plans;
static Times[] times;
public static void main(String[] args) {
InputReader in = new InputReader(System.in, " \n");
PrintWriter out = new PrintWriter(System.out);
int n = in.nextInt() + 1, max = 0, end = n;
plans = new int[n];
times = new Times[n];
int[] dpLen = new int[n];
for (int i = 1;i < n; i++) times[i] = new Times(i, in.nextInt(), in.nextInt());
Arrays.sort(times, 1, n);
for (int i = 1; i < n; i++) {
for (int j = 1; j < i; j++)
if (times[i].begin > times[j].end)
if (dpLen[j] > dpLen[i]) dpLen[i] = dpLen[plans[i] = j];
else if (dpLen[j] == dpLen[i] && consult(plans[i], j)) plans[i] = j;
if (++dpLen[i] == 1) plans[i] = 0;
if (dpLen[i] > max) max = dpLen[end = i];
else if (dpLen[i] == max && times[i].id < times[end].id) end = i;
}
out.println(max);
Queue<Integer> queue = new PriorityQueue();
while (end != 0) {
queue.offer(times[end].id);
end = plans[end];
}
while (queue.size() > 0) out.print(queue.poll() + " ");
out.close();
}
static boolean consult(int i, int j) {
Queue<Integer> queue1 = new PriorityQueue();
Queue<Integer> queue2 = new PriorityQueue();
while (i != 0) { queue1.offer(times[i].id); i = plans[i]; }
while (j != 0) { queue2.offer(times[j].id); j = plans[j]; }
while (queue1.size() > 0) if (queue1.poll() > queue2.poll()) return true;
return false;
}
static class Times implements Comparable<Times> {
int begin;
int end;
int id;
Times(int id, int begin, int end) {
this.id = id;
this.end = end;
this.begin = begin;
}
@Override
public int compareTo(Times t) {
return this.begin - t.begin;
}
}
static class InputReader {
BufferedReader read;
StringTokenizer token;
String delimiters;
InputReader(InputStream in) { this(in, " \t\n\r\f"); }
InputReader(InputStream in, String delimiters) {
this.read = new BufferedReader(new InputStreamReader(in));
this.token = new StringTokenizer("", this.delimiters = delimiters);
}
String next() {
while (!token.hasMoreTokens())
try {
this.token = new StringTokenizer(read.readLine(), delimiters);
} catch (IOException e) {
e.printStackTrace();
}
return token.nextToken();
}
int nextInt() { return Integer.parseInt(next()); }
}
}
如果在字典序比较时,把最小值保存起来,如果最小值相等,再遍历出路径进行比较的话
可能可以到 1s 内,但这样内存就超过了 512.0MB 的限制,大概
先去吃个饭