Problem 2101 大三的美好时光
Accept: 69 Submit: 387
Time Limit: 3000 mSec Memory Limit : 32768 KB
Problem Description
依稀记得自己踏入福大时学长学姐的甜美笑脸,可是一转眼的功夫自己就是大三的学长了。时间匆匆而过也就算了,bluesun痛苦的是,到大三了校选课还没有修满,再加上院选和必修课,bluesun的大三注定是异常辛苦的一年。
Bluesun总是喜欢把要做的事情在最短的时间里做完,所以他决定在必修课必选之外,选择一种使自己可以得到最多学分的方案(不管是院选的学分还是校选的,bluesun只要求学分尽量多)。
Input
数据有多组,请处理到文件结尾。
每组数据的第一行为n(n表示有n门课程可供选择)接下来n行,每行4个整数,t 、l、 r和 v,如果t==0,则表示这门课程是必修课,否则为院选课或者是校选课,l和r表示该门课程占用的时间段为[l,r],v表示该门课程占几个学分。
输入数据均为整数,并且保证必修课的时间不会有交叉,1<=n<=100000,0<=v<=10000,1<=l<=r<=2^30。
Output
每组测试输出一个整数,每个整数占1行,表示bluesun这个学期最多可以修多少个学分。
Sample Input
11 1 1 2
Sample Output
2
Source
FOJ有奖月赛-2012年11月
POINT:
离散化后长度最多20W。用r从小到大排序。Dp的时候把和必修课冲突的课去除。
重点是怎么判断和必修课冲突,利用sum数组,必修课的时间全部sum[time]=1。然后利用前缀和,就知道一段区间里有没有1了。o(1)的效率查询。
#include <string>
#include <string.h>
#include <iostream>
#include <queue>
#include <math.h>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 100000+55;
int temp[maxn*2];
int sum[maxn*2];
int dp[maxn*2];
struct node
{
int t,l,r,v;
}a[maxn];
bool cmd(node a,node b)
{
return a.r<b.r;
}
int main()
{
int n;
while(~scanf("%d",&n)){
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%d %d %d %d",&a[i].t,&a[i].l,&a[i].r,&a[i].v);
temp[++cnt]=a[i].l;
temp[++cnt]=a[i].r;
sum[i]=sum[n+i]=0;
}
sort(temp+1,temp+1+cnt);
int sz=unique(temp+1,temp+1+cnt)-temp-1;
int val=0;
for(int i=1;i<=n;i++){
a[i].l=lower_bound(temp+1, temp+1+sz, a[i].l)-temp;
a[i].r=lower_bound(temp+1, temp+1+sz, a[i].r)-temp;
if(!a[i].t){
for(int j=a[i].l;j<=a[i].r;j++) sum[j]=1;
val+=a[i].v;
}
}
for(int i=1;i<=sz;i++){
sum[i]+=sum[i-1];
dp[i]=0;
}
sort(a+1,a+1+n,cmd);
for(int i=1,j=1;i<=sz;i++){
dp[i]=dp[i-1];
for(;j<=n&&a[j].r==i;j++){
if(a[j].t&&sum[a[j].r]-sum[a[j].l-1]==0){
dp[i]=max(dp[i],dp[a[j].l-1]+a[j].v);
}
}
}
printf("%d\n",val+dp[sz]);
}
return 0;
}