c
n
t
[
l
]
[
r
]
cnt[l][r]
cnt[l][r] 表示包含于
[
l
,
r
]
[l,r]
[l,r] 的区间个数
计算两个 DP 值
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示
[
1
,
i
]
[1,i]
[1,i] 内,第一个数轴放了
j
j
j 个区间,第二个数轴最多能放多少个区间
g
[
i
]
[
j
]
g[i][j]
g[i][j] 表示
[
i
,
m
]
[i,m]
[i,m] 内,第一个数轴放了
j
j
j 个区间,第二个数轴最多能放多少个区间
上面
m
m
m 表示区间的最右边界
转移显然
f
[
i
]
[
j
]
=
max
k
=
0
i
−
1
max
(
f
[
k
]
[
j
−
c
n
t
[
k
+
1
]
[
i
]
]
,
f
[
k
]
[
j
]
+
c
n
t
[
k
+
1
]
[
i
]
)
f[i][j]=\max_{k=0}^{i-1}\max(f[k][j-cnt[k+1][i]],f[k][j]+cnt[k+1][i])
f[i][j]=k=0maxi−1max(f[k][j−cnt[k+1][i]],f[k][j]+cnt[k+1][i])
g
[
i
]
[
j
]
=
max
k
=
i
+
1
m
+
1
max
(
g
[
k
]
[
j
−
c
n
t
[
i
]
[
k
−
1
]
]
,
g
[
k
]
[
j
]
+
c
n
t
[
i
]
[
k
−
1
]
)
g[i][j]=\max_{k=i+1}^{m+1}\max(g[k][j-cnt[i][k-1]],g[k][j]+cnt[i][k-1])
g[i][j]=k=i+1maxm+1max(g[k][j−cnt[i][k−1]],g[k][j]+cnt[i][k−1])
第一问显然为
max
min
(
i
,
f
[
m
]
[
i
]
)
\max\min(i,f[m][i])
maxmin(i,f[m][i])
对于第二问,要强制选择第
i
i
i 个区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]
就相当于选取
l
l
l 和
r
r
r 使得
l
≤
l
i
≤
r
i
≤
r
l\le l_i\le r_i\le r
l≤li≤ri≤r ,强制选择包含于
[
l
,
r
]
[l,r]
[l,r] 的所有的区间
然后包含于
[
1
,
l
−
1
]
[1,l-1]
[1,l−1] 和包含于
[
r
+
1
,
m
]
[r+1,m]
[r+1,m] 的区间分别处理
于是再定义
h
[
l
]
[
r
]
h[l][r]
h[l][r] 表示强制选择包含于
[
l
,
r
]
[l,r]
[l,r] 的区间时,区间个数较少的数轴的区间个数的最大值
转移
h
[
l
]
[
r
]
=
max
i
max
j
min
(
i
+
j
+
c
n
t
[
l
]
[
r
]
,
f
[
l
−
1
]
[
i
]
+
g
[
r
+
1
]
[
j
]
)
h[l][r]=\max_i\max_j\min(i+j+cnt[l][r],f[l-1][i]+g[r+1][j])
h[l][r]=imaxjmaxmin(i+j+cnt[l][r],f[l−1][i]+g[r+1][j])
这是
O
(
n
4
)
O(n^4)
O(n4) 的,过不去
考虑对
f
f
f 和
g
g
g 求后缀最大值
f
[
i
]
[
j
]
f[i][j]
f[i][j] 表示
[
1
,
i
]
[1,i]
[1,i] ,第一个数轴至少选了
j
j
j 个区间
g
[
i
]
[
j
]
g[i][j]
g[i][j] 表示
[
i
,
m
]
[i,m]
[i,m] ,第一个数轴至少选了
j
j
j 个区间
易得
f
f
f 和
g
g
g 的第二维单调不增
同时对于一个转移
i
i
i ,
min
(
i
+
j
+
c
n
t
[
l
]
[
r
]
,
f
[
l
−
1
]
[
i
]
+
g
[
r
+
1
]
[
j
]
)
\min(i+j+cnt[l][r],f[l-1][i]+g[r+1][j])
min(i+j+cnt[l][r],f[l−1][i]+g[r+1][j]) 是关于
j
j
j 的上凸函数
当
i
i
i 减少时最优转移的
j
j
j 递增
可以用 two pointers 维护
i
i
i ,和最优的
j
j
j
强制选第
i
i
i 个区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 的答案为
max
j
=
1
l
i
max
k
=
r
i
m
h
[
j
]
[
k
]
\max_{j=1}^{l_i}\max_{k=r_i}^mh[j][k]
j=1maxlik=rimaxmh[j][k]
复杂度
O
(
n
3
)
O(n^3)
O(n3)
Code
发现常数巨大,果然蒟蒻
#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define For(i, a, b) for (i = a; i <= b; i++)#define Rof(i, a, b) for (i = a; i >= b; i--)inlineintread(){int res =0;bool bo =0;char c;while(((c =getchar())<'0'|| c >'9')&& c !='-');if(c =='-') bo =1;else res = c -48;while((c =getchar())>='0'&& c <='9')
res =(res <<3)+(res <<1)+(c -48);return bo ?~res +1: res;}template<classT>inline T Max(const T &a,const T &b){return a > b ? a : b;}template<classT>inline T Min(const T &a,const T &b){return a < b ? a : b;}constint N =205, M = N <<1, INF =0x3f3f3f3f;int n, l[N], r[N], tm, m, tmp[M], cnt[M][M], f[M][N], g[M][N], le[M], ri[M],
ans, h[M][M];intmain(){int i, j, k;
n =read();
For (i,1, n) l[i]=read(), r[i]= l[i]+read()-1,
tmp[++tm]= l[i], tmp[++tm]= r[i];
std::sort(tmp +1, tmp + tm +1);
m = std::unique(tmp +1, tmp + tm +1)- tmp -1;
For (i,1, n){
l[i]= std::lower_bound(tmp +1, tmp + m +1, l[i])- tmp;
r[i]= std::lower_bound(tmp +1, tmp + m +1, r[i])- tmp;}
For (i,0, m +1) For (j,0, n) f[i][j]= g[i][j]=-INF;
For (i,1, m) For (j, i, m) For (k,1, n)if(i <= l[k]&& r[k]<= j) cnt[i][j]++;
f[0][0]= g[m +1][0]=0;
For (i,1, m) For (j,0, n) For (k,0, i -1){
f[i][j]=Max(f[i][j], f[k][Max(0, j - cnt[k +1][i])]);
f[i][j]=Max(f[i][j], f[k][j]+ cnt[k +1][i]);}
Rof (i, m,1) For (j,0, n) For (k, i +1, m +1){
g[i][j]=Max(g[i][j], g[k][Max(0, j - cnt[i][k -1])]);
g[i][j]=Max(g[i][j], g[k][j]+ cnt[i][k -1]);}
For (i,1, m) For (j,0, n){
le[i]=Max(le[i],Min(j, f[i][j]));
ri[i]=Max(ri[i],Min(j, g[i][j]));}
For (i,0, n) ans =Max(ans,Min(i, f[m][i]));
std::cout << ans << std::endl;
For (i,0, m +1) Rof (j, n -1,0){
f[i][j]=Max(f[i][j], f[i][j +1]);
g[i][j]=Max(g[i][j], g[i][j +1]);}
For (i,1, m) For (j, i, m){int p =0;
Rof (k, n,0){while(p < n &&Min(k + p + cnt[i][j], f[i -1][k]+ g[j +1][p])<Min(k + p +1+ cnt[i][j], f[i -1][k]+ g[j +1][p +1]))
p++;
h[i][j]=Max(h[i][j],Min(k + p + cnt[i][j],
f[i -1][k]+ g[j +1][p]));}}
For (i,1, n){
ans =0;
For (j,1, l[i]) For (k, r[i], m)
ans =Max(ans, h[j][k]);printf("%d\n", ans);}return0;}