传送门

首先可以把时间区间离散化

然后求出 $cnt[l][r]$ 表示完全在时间 $[l,r]$ 之内的活动数量

设 $f[i][j]$ 表示当前考虑到时间 $i$,第一个会场活动数量为 $j$ 时,另一个会场的最大活动数量

这个转移直接枚举上一个时间分界线 $k$, $f[i][j]=max(f[k][j]+cnt[k][i])$ 表示 $[k,i]$ 时间的活动给第二个会场

$f[i][j]=max(f[k][j-cnt[k][i]])$ 表示 $[k,i]$ 时间的活动给第一个会场

这样第一问没有限制的最大数量就可以求出

考虑强制选某个的情况,那么我们可以把时间分成三部分,左右两边和中间强制选的一段时间

左边的贡献可以用 $f$ 求出,同理我们考虑设 $g[i][j]$ 表示当前从 $i$ 考虑到结束,第一个会场活动数量为 $j$ 时,另一个会场的最大活动数量

那么右边的贡献也可以求出,考虑设 $h[i][j]$ 表示 $[i,j]$ 的活动强制选时的最大答案

考虑枚举左右两边的 $j$ 分别为 $x,y$,即第一个会场活动数量

那么有 $h[L][R]=min(x+y+cnt[L][R],f[L][x]+g[R][y])$,这样总复杂度是 $n^4$ 的,考虑关于单调性的优化

发现转移时,对于某个 $x=a$,此时 $y=b$ 最优,那么对于 $x=a+1$,最优点 $y'<=b$

因为第一个会场活动多了第二个就少了,答案就会越来越小

所以枚举 $x$ 的时候动态维护 $y$ 指针即可,复杂度 $O(n^3)$

注意最后每一个的答案是枚举 $L<=a[i].l,R>=a[i].r$ 中的 $h[L][R]$ 取 $max$,而不是直接 $h[a[i].l][a[i].r]$

($a[i].l,a[i].r$ 表示第 $i$ 个活动的时间区间)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=,INF=1e9+;
int n,d[N],m;
struct act{
int l,r;
}a[N];
int cnt[N][N],f[N][N],g[N][N],h[N][N];
inline int calc(int L,int R,int x,int y) { return min(x+y+cnt[L][R] , f[L][x]+g[R][y]); }
int main()
{
n=read();
for(int i=;i<=n;i++)
{
a[i].l=read(),a[i].r=a[i].l+read();
d[i]=a[i].l,d[n+i]=a[i].r;
}
sort(d+,d+*n+); m=unique(d+,d+*n+)-d-;
for(int i=;i<=n;i++)
{
a[i].l=lower_bound(d+,d+m+,a[i].l)-d;
a[i].r=lower_bound(d+,d+m+,a[i].r)-d;
}
for(int l=;l<=m;l++)
for(int r=l+;r<=m;r++)
for(int i=;i<=n;i++)
cnt[l][r]+=(a[i].l>=l&&a[i].r<=r);
for(int i=;i<=m;i++)
for(int j=;j<=n;j++) f[i][j]=g[i][j]=-INF;
for(int i=;i<=m;i++)
for(int j=;j<=cnt[][i];j++)
for(int k=;k<i;k++)
{
f[i][j]=max(f[i][j],f[k][j]+cnt[k][i]);
if(j>=cnt[k][i]) f[i][j]=max(f[i][j],f[k][j-cnt[k][i]]);
}
for(int i=m-;i>=;i--)
for(int j=;j<=cnt[i][m];j++)
for(int k=i+;k<=m;k++)
{
g[i][j]=max(g[i][j],g[k][j]+cnt[i][k]);
if(j>=cnt[i][k]) g[i][j]=max(g[i][j],g[k][j-cnt[i][k]]);
}
// min( x+y+cnt[L][R] , f[L][x]+f[R][y] )
for(int L=;L<=m;L++)
for(int R=L+;R<=m;R++)
for(int x=,y=n;x<=n;x++)
{
while(y&&calc(L,R,x,y)<=calc(L,R,x,y-)) y--;
h[L][R]=max(h[L][R],calc(L,R,x,y));
}
int ans=; for(int i=;i<=n;i++) ans=max(ans,min(f[m][i],i));
printf("%d\n",ans);
for(int i=;i<=n;i++)
{
ans=;
for(int L=;L<=a[i].l;L++)
for(int R=a[i].r;R<=m;R++) ans=max(ans,h[L][R]);
printf("%d\n",ans);
}
return ;
}

P1973 [NOI2011]Noi嘉年华的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

  7. NOI2011 NOI嘉年华

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

  8. bzoj2436: [Noi2011]Noi嘉年华

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

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

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

随机推荐

  1. [POI2017] Flappy Bird

    问题描述 <飞扬的小鸟>是一款风靡的小游戏.在游戏中,小鸟一开始位于(0,0)处,它的目标是飞到横坐标为X的某个位置上.每一秒,你可以选择点击屏幕,那么小鸟会从(x,y)飞到(x+1,y+ ...

  2. visual studio 2017激活

    VS2017专业版和企业版激活密钥   Enterprise: NJVYC-BMHX2-G77MM-4XJMR-6Q8QF Professional: KBJFW-NXHK6-W4WJM-CRMQB- ...

  3. PHP培训教程 PHP里10个鲜为人知但却非常有用的函数

    php里有非常丰富的内置函数,很多我们都用过,但仍有很多的函数我们大部分人都不熟悉,可它们却十分的有用.这篇文章里,兄弟连小编列举了一些鲜为人知但会让你眼睛一亮的PHP函数. levenshtein( ...

  4. JS&ASPDotNet_大文件上传问题

    HTML部分 <%@PageLanguage="C#"AutoEventWireup="true"CodeBehind="index.aspx. ...

  5. UOJ #228. 基础数据结构练习题 线段树 + 均摊分析 + 神题

    题目链接 一个数被开方 #include<bits/stdc++.h> #define setIO(s) freopen(s".in","r",st ...

  6. 【CF10D】LCIS(LCIS)

    题意:求两个序列的LCIS n,m<=300,a[i]<=1e9 题意:O(n^2) O(n^3)的话设dp[i,j]为A终点为a[1..i]且B终点为b[j]的最大长度,分a[i]==b ...

  7. 【HDOJ6731】Angle Beats(极角排序)

    题意:二维平面上给定n个整点,q个询问 每个询问给定另外的一个整点,问其能与n个整点中任意取2个组成的直角三角形的个数 保证所有点位置不同 n<=2e3,q<=2e3,abs(x[i],y ...

  8. 基于点云的3ds Max快速精细三维建模方法及系统的制作方法 插件开发

                                 基于点云的3ds Max快速精细三维建模方法及系统的制作方法[技术领域][0001]本发明涉及数字城市三维建模领域,尤其涉及一种基于点云的3d ...

  9. 洛谷P1982 小朋友的数字——题解

    题目传送 简单地说,这题就是让我们求前i个数的最大子串和和最值. 对于最大子串和,我们可以设一个变量qian,表示以当前元素结尾的最大子串的子串和.若搜索完第i-1个小朋友,现在看到第i个小朋友时,若 ...

  10. SpringBoot:运行原理探究

    西部开源-秦疆老师:基于SpringBoot 2.1.6 的博客教程 秦老师交流Q群号: 664386224 未授权禁止转载!编辑不易 , 转发请注明出处!防君子不防小人,共勉! SpringBoot ...