luogu P1973 [NOI2011]NOI 嘉年华 dp
LINK:NOI 嘉年华
一道质量非常高的dp题目。
考虑如何求出第一问 容易想到dp.
按照左端点排序/右端点排序状态还是很难描述。
但是我们知道在时间上肯定是一次选一段 所以就可以直接利用时间点来dp.
直接将时间离散再做 因为有两个元素使得最大的最小 二分是无意义的。
每次选择是一段所以没必要知道上次选到的时间点在哪 直接枚举上次决策。
分别记录两个地方的值是否存在也是可以优化的 可以只记录一个然后第二个变成最多拿到多少即可。
这样就有状态\(f_{i,j}\)表示到了i这个时间点第一个的值为j的时候第二个的最大值。
转移枚举k 然后预处理\(c_{i,j}\)表示这段时间的任务数即可。
复杂度\(n^3\)
考虑第二问。强制选择某个点 在dp中是很难做到的 所以可以考虑强行将某个区间给第一个会场然后求出第二个会场的最大值。
强行给的话这个地方可以使用前后包夹做 即再做一个后缀dp g数组。
那么强行包含\(l,r\)的最大dp值就是 \(ans_{l,r}=\sum_{x}\sum_{y}max(x+y+c_{l,r},f_{l,x}+g_{r,y})\)
求出这个东西看似是\(n^4\)的 实际上随着x的增大y是不增的。
证明这一点可以进行比较繁杂的分类讨论 不过可以比较直观的想出来。这里不再赘述。
所以可以优化到\(n^3\).
考虑最后的答案 对于一个询问l,r 答案不一定是\(l,r\) 因为此时是把l r单独给抽出来了。
可能一些大的区间一起并且包含其可能是最优的 所以此时枚举包含这个区间的一些区间取max即可。
总复杂度\(n^3\).
code
//#include<bits\stdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define gi(x) scanf("%lf",&x)
#define put(x) printf("%d\n",x)
#define putl(x) printf("%lld\n",x)
#define gc(a) scanf("%s",a+1)
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define vep(p,n,i) for(RE int i=p;i<n;++i)
#define pii pair<int,int>
#define mk make_pair
#define RE register
#define P 1000000007
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define EPS 1e-4
#define sq sqrt
#define S second
#define F first
#define mod 1000000007
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=410;
int n,m,cnt;
int b[MAXN];
int f[MAXN][MAXN],g[MAXN][MAXN],c[MAXN][MAXN],ans[MAXN][MAXN];
struct wy{int l,r;}t[MAXN];
int main()
{
//freopen("1.in","r",stdin);
get(n);
rep(1,n,i)
{
int get(l),get(r)+l;
t[i]=(wy){l,r};
b[++cnt]=l;b[++cnt]=r;
}
sort(b+1,b+1+cnt);
rep(1,cnt,i)if(i==1||b[i]!=b[i-1])b[++m]=b[i];
rep(1,n,i)
{
t[i].l=lower_bound(b+1,b+1+m,t[i].l)-b;
t[i].r=lower_bound(b+1,b+1+m,t[i].r)-b;
rep(1,t[i].l,j)rep(t[i].r,m,k)++c[j][k];
//cout<<t[i].l<<' '<<t[i].r<<endl;
}
memset(f,0xcf,sizeof(f));
memset(g,0xcf,sizeof(g));
f[1][0]=0;g[m][0]=0;
rep(2,m,i)rep(0,c[1][i],j)
{
rep(1,i-1,k)
{
f[i][j]=max(f[i][j],f[k][j]+c[k][i]);
if(j>=c[k][i])f[i][j]=max(f[i][j],f[k][j-c[k][i]]);
}
//cout<<i<<' '<<j<<' '<<f[i][j]<<endl;
}
fep(m-1,1,i)rep(0,c[i][m],j)rep(i+1,m,k)
{
g[i][j]=max(g[i][j],g[k][j]+c[i][k]);
if(j>=c[i][k])g[i][j]=max(g[i][j],g[k][j-c[i][k]]);
}
rep(1,m,i)
{
rep(i,m,j)
{
int y=n;
rep(0,n,x)
{
while(y&&min(c[i][j]+x+y,f[i][x]+g[j][y])<=min(c[i][j]+x+y-1,f[i][x]+g[j][y-1]))--y;
ans[i][j]=max(ans[i][j],min(c[i][j]+x+y,f[i][x]+g[j][y]));
}
//cout<<i<<' '<<j<<' '<<ans[i][j]<<endl;
}
}
int ww=0;
rep(1,n,i)ww=max(ww,min(i,f[m][i]));
put(ww);
rep(1,n,i)
{
ww=0;
rep(1,t[i].l,j)rep(t[i].r,m,k)ww=max(ww,ans[j][k]);
put(ww);
}
return 0;
}
luogu P1973 [NOI2011]NOI 嘉年华 dp的更多相关文章
- 洛谷P1973 [NOI2011]Noi嘉年华(动态规划,决策单调性)
洛谷题目传送门 DP题怕是都要大大的脑洞...... 首先,时间那么大没用,直接离散化. 第一问还好.根据题意容易发现,当一堆活动的时间有大量重叠的时候,更好的办法是把它们全部安排到一边去.那么我们转 ...
- 洛谷P1973 [NOI2011]Noi嘉年华(决策单调性)
传送门 鉴于FlashHu大佬讲的这么好(而且我根本不会)我就不再讲一遍了->传送 //minamoto #include<iostream> #include<cstdio& ...
- cogs 1377. [NOI2011] NOI嘉年华 (dp
题意:给你n个活动的起止时间,要你从中选一些活动在2个会场安排(不能有两个活动在两个会场同时进行),使活动较少的会场活动数最大,以及在某个活动必须选择的前提下,求该答案. 思路:由于n很小,时间很大, ...
- P1973 [NOI2011]Noi嘉年华
传送门 首先可以把时间区间离散化 然后求出 $cnt[l][r]$ 表示完全在时间 $[l,r]$ 之内的活动数量 设 $f[i][j]$ 表示当前考虑到时间 $i$,第一个会场活动数量为 $j$ 时 ...
- 【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 嘉年华活动,分在两个不同的地点举办.每个嘉年华可能包含很多个活动, ...
- BZOJ2436 [Noi2011]Noi嘉年华 【dp】
题目链接 BZOJ2436 题解 看这\(O(n^3)\)的数据范围,可以想到区间\(dp\) 发现同一个会场的活动可以重叠,所以暴力求出\(num[l][r]\)表示离散化后\([l,r]\)的完整 ...
- bzoj2436: [Noi2011]Noi嘉年华
我震惊了,我好菜,我是不是该退役(苦逼) 可以先看看代码里的注释 首先我们先考虑一下第一问好了真做起来也就这个能想想了 那么离散化时间是肯定的,看一手范围猜出是二维DP,那对于两个会场,一个放自变量, ...
随机推荐
- 揭秘JAVA JVM内幕
在之前的文章 一步步解析java执行内幕 中,比较详细分析了java代码是如何一步一步在jvm中执行的,然而设计的的jvm核心技术点,并未做深入分析,本篇文章将重点分析jvm,涉及到的内容包括jvm内 ...
- 【第五空间智能安全大赛】hate_php WriteUp
环境:https://www.ctfhub.com/#/challenge 打开题目可以看到源码: 阅读源码发现过滤掉了f l a g . p h / ; " ' ` | [ ] _ =这些 ...
- Java实现上传文件到指定服务器指定目录(ChannelSftp实现文件上传下载)
package com.tianyang.task.utils; import java.io.File;import java.io.FileInputStream;import java.io.I ...
- 浏览器访问 www.baidu.com 的过程
浏览器访问 www.baidu.com 的过程 1 先要解析出www.baidu.com DNS域名解析为服务器 IP 2 得到 IP地址后,客户端会发起TCP请求,以及3次握手建立连接 3 建立连接 ...
- day54 作业
编写代码,将当前日期按"2017-12-27 11:11 星期三"格式输出(提示:switch结构) var date = new Date() ymd = data.toLoca ...
- DVWA学习记录 PartⅨ
XSS(DOM) 1. 题目 XSS,全称Cross Site Scripting,即跨站脚本攻击,某种意义上也是一种注入攻击,是指攻击者在页面中注入恶意的脚本代码,当受害者访问该页面时,恶意代码会在 ...
- 【python】Anaconda4 linux/windos安装
一.什么是Anaconda 二.Win10 安装Anaconda 三.Linu 安装Anaconda ------------------------------------------------- ...
- node子进程(Child Process)获取硬盘分区
node child_process文档 child_process.exec(command[, options][, callback]) command <string> The ...
- MYSQL 之 JDBC(十四):批量处理JDBC语句提高处理效率
1.当需要成批插入或者更新记录时.可以采用java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理.通常情况下比单独提交处理更有效率. 2.JDBC的批量处理语句包括下面两个方法: ad ...
- java学习第七天2020/7/12
一. java继承使用的关键字是 extend class 子类 extends 父类{} 举一个类的例子: public class person { public String name; pu ...