【BZOJ2436】NOI嘉年华(动态规划)

题面

BZOJ

题解

考虑第一问如何求解

发现状态与选择了哪些活动无关,只与时间有关

设\(f[i][j]\)表示前\(i\)个单位时间(离散后),一个嘉年华选择了\(j\)个活动时

另外一个可以选择的最多的活动数量

转移的话枚举一下转移过来的时间\(k\)

考虑时间\([k..i]\)的活动分配给哪个嘉年华就好了

所以\(f[i][j]=max(f[k][j]+sum[k][i],f[k][j-sum[k][i]])\)

其中\(sum[i][j]\)表示时间\([i,j]\)中能够进行的所有活动的数量。

时间复杂度\(O(n^3)\)

考虑第二问

显然是中间一段强制选,然后剩下的地方被拆成了两段

然后考虑最大值。

注意,这强制选的一段不一定恰好是当前必须选的活动的这一段时间

而是可以向两边拓展

所以我们需要先预处理\(dp[i][j]\)表示时间\([i,j]\)的所有活动必须选择的最优值

设\(g[i][j]\)和\(f\)表示相同的含义,但是时间不是\([1,i]\)而是\([i,n]\),即倒着选。

枚举前面和后面分割出来的时间某个嘉年华分别选择了几个活动,

这样很容易转移,相当于是把中间强制选择的那段时间的所有活动直接加给活动较少的那个嘉年华。

但是这样的复杂度是\(O(n^4)\)的。

我们需要优化这个转移,假设枚举选择了多少个活动的那个嘉年华

在强制选择的区间的前面选了\(x\)个活动,后面选了\(y\)个活动

发现当\(x\)增大时,另外一个嘉年华能够选择的个数会减小,

而中间强制选择的区间的值不会变化,如果继续增加\(y\)的话,发现另外一个嘉年华能够选择的值也会更小,所以\(x\)增加时,\(y\)减少。

这样子可以利用单调性优化掉一个\(n\),时间复杂度变为\(O(n^3)\)。

每次回答询问的时候,确定当前强制选择的活动左右端点,暴力向左右拓展就好了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 444
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int L[MAX],R[MAX],S[MAX],tot,num[MAX][MAX];
int f[MAX][MAX],g[MAX][MAX],d[MAX][MAX],ans,n;
void cmax(int &x,int y){if(x<y)x=y;}
int Calc(int i,int j,int x,int y)
{
if(f[i][x]<0||g[j][y]<0)return -1e9;
int t=f[i][x]+g[j][y];
return min(max(t,x+y),min(t,x+y)+num[i][j]);
}
int main()
{
n=read();
for(int i=1;i<=n;++i)L[i]=read(),R[i]=read()+L[i];
for(int i=1;i<=n;++i)S[++tot]=L[i],S[++tot]=R[i];
sort(&S[1],&S[tot+1]);tot=unique(&S[1],&S[tot+1])-S-1;
for(int i=1;i<=n;++i)L[i]=lower_bound(&S[1],&S[tot+1],L[i])-S;
for(int i=1;i<=n;++i)R[i]=lower_bound(&S[1],&S[tot+1],R[i])-S;
for(int i=0;i<=tot+1;++i)
for(int j=i;j<=tot+1;++j)
for(int k=1;k<=n;++k)
if(i<=L[k]&&R[k]<=j)++num[i][j];
memset(f,-63,sizeof(f));f[0][0]=0;
for(int i=1;i<=tot;++i)
for(int j=0;j<=n;++j)
for(int k=0;k<i;++k)
{
cmax(f[i][j],f[k][j]+num[k][i]);
if(j>=num[k][j])cmax(f[i][j],f[k][j-num[k][i]]);
}
for(int i=1;i<=tot;++i)ans=max(ans,min(i,f[tot][i]));
printf("%d\n",ans);
memset(g,-63,sizeof(g));g[tot+1][0]=0;
for(int i=tot;i;--i)
for(int j=0;j<=n;++j)
for(int k=i+1;k<=tot+1;++k)
{
cmax(g[i][j],g[k][j]+num[i][k]);
if(j>=num[k][j])cmax(g[i][j],g[k][j-num[i][k]]);
}
for(int i=1;i<=tot;++i)
for(int j=i;j<=tot;++j)
if(num[i][j])
{
int y=n;
for(int x=0;x<=n;++x)
{
int nw=Calc(i,j,x,y);
while(y)
{
int nt=Calc(i,j,x,y-1);
if(nw<=nt)--y,nw=nt;
else break;
}
d[i][j]=max(d[i][j],nw);
}
}
for(int i=1;i<=n;++i)
{
ans=0;
for(int j=1;j<=L[i];++j)
for(int k=R[i];k<=tot;++k)
ans=max(ans,d[j][k]);
printf("%d\n",ans);
}
return 0;
}

【BZOJ2436】【NOI2011】NOI嘉年华(动态规划)的更多相关文章

  1. BZOJ2436 [Noi2011]Noi嘉年华 【dp】

    题目链接 BZOJ2436 题解 看这\(O(n^3)\)的数据范围,可以想到区间\(dp\) 发现同一个会场的活动可以重叠,所以暴力求出\(num[l][r]\)表示离散化后\([l,r]\)的完整 ...

  2. bzoj2436: [Noi2011]Noi嘉年华

    我震惊了,我好菜,我是不是该退役(苦逼) 可以先看看代码里的注释 首先我们先考虑一下第一问好了真做起来也就这个能想想了 那么离散化时间是肯定的,看一手范围猜出是二维DP,那对于两个会场,一个放自变量, ...

  3. 【BZOJ 2436】 2436: [Noi2011]Noi嘉年华 (区间DP)

    2436: [Noi2011]Noi嘉年华 Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不 ...

  4. 2436: [Noi2011]Noi嘉年华 - BZOJ

    Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办.每个嘉年华可能包含很多个活动, ...

  5. bzoj 2436: [Noi2011]Noi嘉年华

    Description NOI2011 在吉林大学开始啦!为了迎接来自全国各地最优秀的信息学选手,吉林大学决定举办两场盛大的 NOI 嘉年华活动,分在两个不同的地点举办.每个嘉年华可能包含很多个活动, ...

  6. luogu P1973 [NOI2011]NOI 嘉年华 dp

    LINK:NOI 嘉年华 一道质量非常高的dp题目. 考虑如何求出第一问 容易想到dp. 按照左端点排序/右端点排序状态还是很难描述. 但是我们知道在时间上肯定是一次选一段 所以就可以直接利用时间点来 ...

  7. 洛谷P1973 [NOI2011]Noi嘉年华(动态规划,决策单调性)

    洛谷题目传送门 DP题怕是都要大大的脑洞...... 首先,时间那么大没用,直接离散化. 第一问还好.根据题意容易发现,当一堆活动的时间有大量重叠的时候,更好的办法是把它们全部安排到一边去.那么我们转 ...

  8. NOI2011 NOI嘉年华

    http://www.lydsy.com/JudgeOnline/problem.php?id=2436 首先离散化,离散化后时间范围为[1,cnt]. 求出H[i][j],表示时间范围在[i,j]的 ...

  9. 洛谷P1973 [NOI2011]Noi嘉年华(决策单调性)

    传送门 鉴于FlashHu大佬讲的这么好(而且我根本不会)我就不再讲一遍了->传送 //minamoto #include<iostream> #include<cstdio& ...

  10. cogs 1377. [NOI2011] NOI嘉年华 (dp

    题意:给你n个活动的起止时间,要你从中选一些活动在2个会场安排(不能有两个活动在两个会场同时进行),使活动较少的会场活动数最大,以及在某个活动必须选择的前提下,求该答案. 思路:由于n很小,时间很大, ...

随机推荐

  1. ln in Linux

    默认情况(硬连接) ln 目标 连接名称 ll -i 显示文件的inode信息,即文件节点信息 ➜  test1 ll -i 1.txt 27987655 -rw-r--r--  1 myuser   ...

  2. 用php实现简单的自制计算器

    存档: <!DOCTYPE html> <html> <head> <title>PHP实现计算器</title> </head> ...

  3. [原创软件]PC端与移动端文件信息互通工具

    一个不小心,花了几个小时,就做出来了一个专利,这不科学啊... 软件主要功能: 跨平台(已适配Mac.Windows)远程连接手机端和PC端 远程执行shell命令 远程和本地文件实现互通传输共享 显 ...

  4. Jmeter接口测试(一) Jmeter简介

    一.Jmeter介绍 (一)Jmeter简介 Apache JMeter 是 Apache 组织的开放源代码项目,是一个纯 Java 桌面应用,用于压力测试和性能测试.它最初被设计用于 Web 应用测 ...

  5. Vue学习计划基础笔记(六) - 组件基础

    组件基础 目标: 掌握组件的构建方式 掌握如何复用组件.父子组件如何传值.如何向父组件发送消息 掌握如何通过插槽分发内容 了解解析dom模板时的注意事项 了解动态组件 组件 组件理解起来大概上就和ph ...

  6. Python解包参数列表及 Lambda 表达式

    解包参数列表 当参数已经在python列表或元组中但需要为需要单独位置参数的函数调用解包时,会发生相反的情况.例如,内置的 range() 函数需要单独的 start 和 stop 参数.如果它们不能 ...

  7. 【Python进阶】用 Python 统计字数

    问题描述: 用 Python 实现函数 count_words(),该函数输入字符串 s 和数字 n,返回 s 中 n 个出现频率最高的单词.返回值是一个元组列表,包含出现次数最高的 n 个单词及其次 ...

  8. Python3实现机器学习经典算法(二)KNN实现简单OCR

    一.前言 1.ocr概述 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然 ...

  9. #Ubuntu 18.04 安装tensorflow-gpu 1.9

    参考 https://tensorflow.google.cn/install/install_linux http://nvidia.com/cuda http://developer.nvidia ...

  10. Python基础知识-05-数据类型总结字典

    python其他知识目录 1.一道题,选择商品的序号.程序员和用户各自面对的序号起始值 如有变量 googs = ['汽车','飞机','火箭'] 提示用户可供选择的商品: 0,汽车1,飞机2,火箭用 ...