BZOJ2436 [Noi2011]Noi嘉年华 【dp】
题目链接
题解
看这\(O(n^3)\)的数据范围,可以想到区间\(dp\)
发现同一个会场的活动可以重叠,所以暴力求出\(num[l][r]\)表示离散化后\([l,r]\)的完整活动数
我们的目标求出\(F[l][r]\)表示\([l,r]\)必须选时,二者的最小值
我们不妨令\(A\)选了\([l,r]\),我们枚举\(A\)在\([1,l - 1]\)和\([r + 1,tot]\)各选了多少,求出此时\(B\)能选的最大值
如果我们能求出\(f[i][j]\)表示\([1,i]\)中\(A\)选了\(j\)个时\(B\)能选的最大值,\(g[i][j]\)同理表示后缀,就可以求出\(F[l][r]\)
\(f[i][j]\)可以枚举断点\(k\)从而\(O(n^3)\)转移
\]
\(F[l][r]\)的转移是\(O(n^4)\),这个过程中我们\(O(n^2)\)枚举了\(A\)在两端的选取个数
感性理解一下,当\(A\)在左端选多时,为了使答案更优,右端应该选少一些,所以左端增大的同时右端应该是单调变化的
用一个指针维护右端即可\(O(n^3)\)
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u]; k; k = ed[k].nxt)
#define cls(s,v) memset(s,v,sizeof(s))
#define mp(a,b) make_pair<int,int>(a,b)
#define cp pair<int,int>
using namespace std;
const int maxn = 405,maxm = 100005,INF = 100000000;
const double eps = 1e-9;
inline int read(){
	int out = 0,flag = 1; char c = getchar();
	while (c < 48 || c > 57){if (c == '-') flag = 0; c = getchar();}
	while (c >= 48 && c <= 57){out = (out << 1) + (out << 3) + c - 48; c = getchar();}
	return flag ? out : -out;
}
int n,L[maxn],R[maxn],b[maxn],bi,tot;
int f[maxn][maxn],g[maxn][maxn],num[maxn][maxn];
int F[maxn][maxn];
inline int getn(int x){return lower_bound(b + 1,b + 1 + tot,x) - b;}
inline int cal(int l,int r,int x,int y){
	return min(x + y + num[l][r],f[l - 1][x] + g[r + 1][y]);
}
void work(){
	for (int j = 1; j <= n; j++) f[0][j] = -INF;
	for (int i = 1; i <= tot; i++)
		for (int j = 0; j <= n; j++){
			f[i][j] = -INF;
			for (int k = 0; k < i; k++){
				int tmp = -INF;
				if (num[1][k] >= j) tmp = max(tmp,f[k][j] + num[k + 1][i]);
				if (num[k + 1][i] <= j) tmp = max(tmp,f[k][j - num[k + 1][i]]);
				f[i][j] = max(f[i][j],tmp);
			}
		}
	for (int j = 1; j <= n; j++) g[tot + 1][j] = -INF;
	for (int i = tot; i; i--)
		for (int j = 0; j <= n; j++){
			g[i][j] = -INF;
			for (int k = tot + 1; k > i; k--){
				int tmp = -INF;
				if (num[k][tot] >= j) tmp = max(tmp,g[k][j] + num[i][k - 1]);
				if (num[i][k - 1] <= j) tmp = max(tmp,g[k][j - num[i][k - 1]]);
				g[i][j] = max(g[i][j],tmp);
			}
		}
	//REP(i,tot) REP(j,n) printf("f[%d][%d] = %d\n",i,j,f[i][j]);
	int ans = 0;
	for (int i = 0; i <= n; i++)
		ans = max(ans,min(i,f[tot][i]));
	printf("%d\n",ans);
	for (int len = tot; len; len--)
		for (int l = 1; l + len - 1 <= tot; l++){
			int r = l + len - 1,y = num[r + 1][tot];
			F[l][r] = max(F[l - 1][r],F[l][r + 1]);
			for (int x = 0; x <= num[1][l - 1]; x++){
				while (y > 0 && cal(l,r,x,y - 1) >= cal(l,r,x,y)) y--;
				F[l][r] = max(F[l][r],cal(l,r,x,y));
			}
		}
	REP(i,n) printf("%d\n",F[L[i]][R[i]]);
}
int main(){
	n = read();
	REP(i,n){
		b[++bi] = L[i] = read();
		b[++bi] = R[i] = read() + L[i] - 1;
	}
	sort(b + 1,b + 1 + bi); tot = 1;
	for (int i = 2; i <= bi; i++) if (b[i] != b[tot]) b[++tot] = b[i];
	REP(i,n){
		L[i] = getn(L[i]),R[i] = getn(R[i]);
		for (int l = L[i]; l; l--)
			for (int r = R[i]; r <= tot; r++)
				num[l][r]++;
	}
	//REP(i,n) printf("[%d,%d]\n",L[i],R[i]); puts("");
	//printf("%d\n",num[3][5]);
	work();
	return 0;
}
BZOJ2436 [Noi2011]Noi嘉年华 【dp】的更多相关文章
- luogu P1973 [NOI2011]NOI 嘉年华 dp
		LINK:NOI 嘉年华 一道质量非常高的dp题目. 考虑如何求出第一问 容易想到dp. 按照左端点排序/右端点排序状态还是很难描述. 但是我们知道在时间上肯定是一次选一段 所以就可以直接利用时间点来 ... 
- bzoj2436: [Noi2011]Noi嘉年华
		我震惊了,我好菜,我是不是该退役(苦逼) 可以先看看代码里的注释 首先我们先考虑一下第一问好了真做起来也就这个能想想了 那么离散化时间是肯定的,看一手范围猜出是二维DP,那对于两个会场,一个放自变量, ... 
- cogs 1377. [NOI2011] NOI嘉年华 (dp
		题意:给你n个活动的起止时间,要你从中选一些活动在2个会场安排(不能有两个活动在两个会场同时进行),使活动较少的会场活动数最大,以及在某个活动必须选择的前提下,求该答案. 思路:由于n很小,时间很大, ... 
- 【BZOJ 2436】 2436: [Noi2011]Noi嘉年华 (区间DP)
		2436: [Noi2011]Noi嘉年华 Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不 ... 
- 2436: [Noi2011]Noi嘉年华 - BZOJ
		Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办.每个嘉年华可能包含很多个活动, ... 
- bzoj 2436: [Noi2011]Noi嘉年华
		Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办.每个嘉年华可能包含很多个活动, ... 
- NOI2011 NOI嘉年华
		http://www.lydsy.com/JudgeOnline/problem.php?id=2436 首先离散化,离散化后时间范围为[1,cnt]. 求出H[i][j],表示时间范围在[i,j]的 ... 
- 洛谷P1973 [NOI2011]Noi嘉年华(动态规划,决策单调性)
		洛谷题目传送门 DP题怕是都要大大的脑洞...... 首先,时间那么大没用,直接离散化. 第一问还好.根据题意容易发现,当一堆活动的时间有大量重叠的时候,更好的办法是把它们全部安排到一边去.那么我们转 ... 
- 洛谷P1973 [NOI2011]Noi嘉年华(决策单调性)
		传送门 鉴于FlashHu大佬讲的这么好(而且我根本不会)我就不再讲一遍了->传送 //minamoto #include<iostream> #include<cstdio& ... 
随机推荐
- 关于python中的tkinter模块
			python2.7和python3.6中的tkinter是两个包,不会自动升级,假如在fedora28做开发的话, 错误:用import Tkinter /import tkinter /import ... 
- oracle数据库之子查询
			子查询也叫内部查询,在主查询之前执行一次并得到结果,此结果一般情况下,是用来当做是主查询的条件. -- 在 emp 表中,找出工资比 ALLEN 的高? -- 先查出 ALLEN 的工资是多少? ... 
- Spring入门学习笔记(4)——JDBC的使用
			目录 Spring JDBC框架概览 JdbcTemplate类 配置数据源 数据访问对象(Data Access Object,DAO) 执行SQL命令 Spring JDBC框架概览 使用传统的J ... 
- Visionpro介绍和下载安装视频教程
			------------------------Halcon,Visionpro高清视频教程,点击下载视频-------------------------- 
- jobs命令详解
			基础命令学习目录首页 在用管理员执行一个命令后,用Ctrl+Z把命令转移到了后台.导致无法退出root的. 输入命令:exit终端显示:There are stopped jobs. 解决方法:方法一 ... 
- [cmake] Basic Tutorial
			Basic Project The most basic porject is an executable built from source code file. CMakeLists.txt cm ... 
- 冲刺One之站立会议1
			接到任务之后的第一天,大家都分头查找了一些相关资料,目的是最终确定用什么语言编写程序.李琦负责对Java实现聊天室进行调研.郭婷和朱慧敏负责对C#进行调研.李敏和刘子晗负责对QT的实现进行调研.并讨论 ... 
- web窗体之四则运算
			1,计算方法: namespace ASP.NET { public class JiSuan { public int S; public int Result { get { return S; ... 
- C++  MOOC
			相关课程列表: C++远征之起航篇 C++远征之离港篇 C++远征之封装篇 上 C++远征之封装篇 下 C++远征之继承篇 C++远征之多态篇 授课老师:james_yuan 在寒假,我主要选择 C+ ... 
- JAVA中处理事务的程序--多条更新SQL语句的执行(包括回滚)
			在与数据库操作时,如果执行多条更新的SQL语句(如:update或insert语句),在执行第一条后如果出现异常或电脑断电, 则后面的SQL语句执行不了,这时候设定我们自己提交SQL语句,不让JDBC ... 
