Link
https://www.lydsy.com/JudgeOnline/problem.php?id=2436
题意
安排 n n n 个活动,每个活动举办时间 ( s i , t i ) (s_i,t_i) (si,ti) ,同一时间两个场地只能有一个办活动(可以办好多个)。
对于每个询问,钦定一个活动必须举办(或者不钦定),要求最大化举办的活动数量较少的场地举办的活动数量。
输出这个最大值。
好 我又老了
上来先排序离散化
考虑到实际上一个会场选的是“一段时间”,可以预处理出在某一段时间内开始并结束的活动数量 p ( a , b ) p(a,b) p(a,b)
很容易根据上面这东西大概地对转移有个猜想,然后就差不多可以设计出状态:
可以考虑设类似于 f ( k , i ) f(k,i) f(k,i) ,那么前 k k k 个时间,一个场地至多选 i i i 个的时候另一个场地至多选 f ( k , i ) f(k,i) f(k,i) 个
为了方便钦定,相应地考虑可能会设 g ( k , i ) g(k,i) g(k,i) ,那么第 k k k 个时间之后,一个场地至多选 i i i 个的时候下略
考虑转移, f ( k , i ) = max d ∈ [ 0 , k ) max { f ( d , i ) + p ( d , k ) , f ( d , i − p ( d , k ) ) } f(k,i)=\max\limits_{d\in[0,k)}\max\{ f(d,i)+p(d,k),f(d,i-p(d,k))\} f(k,i)=d∈[0,k)maxmax{f(d,i)+p(d,k),f(d,i−p(d,k))}
那么 f f f 和 g g g 都可以 O ( n 3 ) O(n^3) O(n3) 搞出来
然后考虑不加限制时的答案:暴扫一遍都可以搞出来了(。。。
钦定一个活动 等于 钦定了那一整段时间内的都要选
然后两边的怎么做?
如果我们钦定的给某一个场地办,对于另外一个场地可以考虑枚举在钦定左右分别选了几个
好像也搞完了?
a n s ( i , j ) = max x , y { min { x + y , f ( i , x ) + p ( i , j ) + g ( j , y ) } } ans(i,j)=\max\limits_{x,y}\{\min\{x+y,f(i,x)+p(i,j)+g(j,y)\}\} ans(i,j)=x,ymax{min{x+y,f(i,x)+p(i,j)+g(j,y)}}
O ( n 3 ) O(n^3) O(n3) ……?不对。
最终答案并不等于 a n s ( s i , t i ) ans(s_i,t_i) ans(si,ti) 。
(啊啊啊。。要是考起来我大概就被这东西坑爆了)
钦定了 ( L , R ) (L,R) (L,R) ,但是实际上选的区域可能会更大 比如 ( l , r ) , l < L < R < r (l,r),l<L<R<r (l,r),l<L<R<r 这样
显然我们钦定还是有影响到 ( l , L ) (l,L) (l,L) 和 ( R , r ) (R,r) (R,r)
所以我们需要处理出所有的 a n s ( i , j ) ans(i,j) ans(i,j) ,实际上是 O ( n 4 ) O(n^4) O(n4) 的
然后可以搞记忆化搞剪枝等等玄学一发小常数骗分(甚至可能水掉这道题
(我作为一个不会水法选手 记笔记记笔记.jpg
(但是感觉我反而会玄学剪枝剪到常数变大啊(???
关于这部分中间差点掉坑,其实如果运气好是可以避免的
思考钦定某个活动要办,然后考虑枚举一下某个场地覆盖这个活动的那段启用的时间
好像也挺自然的(?)
怎么优化成 O ( n 3 ) O(n^3) O(n3) ?
dp 优化当然要考虑单调性啦,考虑 a n s ( i , j ) = max x , y min ans(i,j)=\max\limits_{x,y}\min ans(i,j)=x,ymaxmin
思考 x , y x,y x,y 最优决策点,那先固定 i , j i,j i,j
不难发现 f ( i , x ) f(i,x) f(i,x) 和 g ( j , y ) g(j,y) g(j,y) 在 i i i 固定的时候有显然的单调性
换成 a n s ( i , j ) = max x , y { min { f ( i , x ) + g ( j , y ) , x + p ( i , j ) + y } } ans(i,j)=\max\limits_{x,y}\{\min\{f(i,x)+g(j,y),x+p(i,j)+y\}\} ans(i,j)=x,ymax{min{f(i,x)+g(j,y),x+p(i,j)+y}}
所以对于最优决策,按照 x , y x,y x,y 中的某一个排序后,按顺序看 x , y x,y x,y 必定是一个变大一个变小
那么维护指针就可以 O ( n ) O(n) O(n) 找出所有最优决策点对 ( x , y ) (x,y) (x,y)
复杂度 O ( n 3 ) O(n^3) O(n3)
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int MAXN = 405;
int n, s[MAXN], t[MAXN], tmp[MAXN], m;
int f[MAXN][MAXN], p[MAXN][MAXN], ans[MAXN][MAXN], g[MAXN][MAXN];
int main()
{
scanf("%d", &n);
for (register int i = 1; i <= n; ++i)
{
scanf("%d%d", &s[i], &t[i]);
t[i] += s[i];
tmp[++m] = s[i], tmp[++m] = t[i];
}
sort(tmp + 1, tmp + 1 + m);
m = unique(tmp + 1, tmp + 1 + m) - tmp - 1;
for (register int i = 1; i <= n; ++i)
{
s[i] = lower_bound(tmp + 1, tmp + 1 + m, s[i]) - tmp;
t[i] = lower_bound(tmp + 1, tmp + 1 + m, t[i]) - tmp;
for (register int l = 1; l <= s[i]; ++l)
for (register int r = t[i]; r <= m; ++r)
++p[l][r];
}
for (register int i = 1; i <= m; ++i)
for (register int j = 1; j <= n; ++j)
f[i][j] = g[i][j] = -0x3f3f3f3f;
for (register int k = 1; k <= m; ++k)
for (register int i = 0; i <= p[1][k]; ++i)
for (register int d = 1; d <= k; ++d)
{
f[k][i] = max(f[k][i], f[d][i] + p[d][k]);
if (i >= p[d][k]) f[k][i] = max(f[k][i], f[d][i-p[d][k]]);
}
for (register int k = m; k >= 1; --k)
for (register int i = 0; i <= p[k][m]; ++i)
for (register int d = k; d <= m; ++d)
{
g[k][i] = max(g[k][i], g[d][i] + p[k][d]);
if (i >= p[k][d]) g[k][i] = max(g[k][i], g[d][i-p[k][d]]);
}
for (register int i = 1; i <= m; ++i)
for (register int j = i + 1; j <= m; ++j)
for (register int fa, c, x = 0, y = n; x <= n; ++x)
{
fa = min(x + p[i][j] + y, f[i][x] + g[j][y]);
while (y)
{
c = min(x + p[i][j] + y - 1, f[i][x] + g[j][y - 1]);
if (fa <= c) fa = c, --y;
else break;
}
ans[i][j] = max(ans[i][j], min(x + p[i][j] + y, f[i][x] + g[j][y]));
}
int Ans = 0;
for (register int i = 1; i <= n; ++i) Ans = max(Ans, min(f[m][i], i));
printf("%d\n", Ans);
for (register int k = 1; k <= n; ++k)
{
Ans = 0;
for (register int i = 1; i <= s[k]; ++i)
for (register int j = m; j >= t[k]; --j)
Ans = max(Ans, ans[i][j]);
printf("%d\n", Ans);
}
return 0;
}