FZU 2101 - 大三的美好时光(离散化+线性DP)

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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值