题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3721
题意:
给出若干课程的上课区间,
若两门课程的上课时间不重叠,则可能有学生同时选修这两门课程,因此不能安排在一天考试。
问至少要安排多少天考试,并输出方案
算法:
线段树优化的DP
首先把课程按照结束时间排序。
对于一个课程,
处理出所有结束时间在它的开始时间之前的课程(也就是与它不相交的课程),
求出它们的考试日期最晚在哪一天,然后把这个日期+1,就得到了这个当前处理的这个课程的最早考试时间。
所有的课程都按照最早考试时间考试,总的考试时间就会最短。
其实这个求解过程的证明不是特别严谨,期待有更严谨的证明。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<climits>
#include<cmath>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define eps 1e-8
using namespace std;
typedef pair<int,int> PII;
const int MAXN=300000;
int s[MAXN],t[MAXN];
int tr[MAXN<<2];
vector<int> hash;
vector<int> ans[MAXN];
vector<pair<PII,int> > a;
int query(int l, int r, int L, int R, int rt) {
if(L<=l&&r<=R) {
return tr[rt];
}
int mid=(l+r)>>1;
int tmp=0;
if(L<=mid) {
tmp=max(tmp,query(l,mid,L,R,rt<<1));
}
if(R>mid) {
tmp=max(tmp,query(mid+1,r,L,R,rt<<1|1));
}
return tmp;
}
void update(int l, int r, int x, int c, int rt) {
tr[rt]=max(tr[rt],c);
if(l==r) {
return;
}
int mid=(l+r)>>1;
if(x<=mid) {
update(l,mid,x,c,rt<<1);
} else {
update(mid+1,r,x,c,rt<<1|1);
}
}
int main() {
int n;
while(scanf("%d",&n)==1) {
hash.clear();
a.clear();
for(int i=1; i<=n; i++) {
ans[i].clear();
}
for(int i=1; i<=n; i++) {
scanf("%d%d",&s[i],&t[i]);
hash.push_back(s[i]);
hash.push_back(t[i]);
a.push_back(make_pair(make_pair(t[i],s[i]),i));
}
sort(hash.begin(),hash.end());
hash.erase(unique(hash.begin(),hash.end()),hash.end());
sort(a.begin(),a.end());
int m=hash.size();
memset(tr,0,sizeof(tr));
for(int i=0; i<n; i++) {
a[i].first.second=lower_bound(hash.begin(),hash.end(),a[i].first.second)-hash.begin();
a[i].first.first=lower_bound(hash.begin(),hash.end(),a[i].first.first)-hash.begin();
}
int num=1;
for(int i=0; i<n; i++) {
int tmp=query(0,m-1,0,a[i].first.second,1)+1;
num=max(num,tmp);
ans[tmp].push_back(a[i].second);
update(0,m-1,a[i].first.first,tmp,1);
}
printf("%d\n",num);
for(int i=1; i<=num; i++) {
sort(ans[i].begin(),ans[i].end());
for(int j=0; j<ans[i].size(); j++) {
if(j) {
printf(" ");
}
printf("%d",ans[i][j]);
}
puts("");
}
}
return 0;
}