发现这要把一段的活动归到一边去
先离散化时间
n
u
m
[
l
]
[
r
]
num[l][r]
num[l][r]表示全部在
[
l
,
r
]
[l,r]
[l,r]内的活动的个数
p
r
e
[
i
]
[
j
]
pre[i][j]
pre[i][j]表示前
i
i
i的时间内给一边
j
j
j个另一边最多有多少个
则
p
r
e
[
i
]
[
j
]
=
M
a
x
k
m
a
x
(
p
r
e
[
k
]
[
j
]
+
n
u
m
[
k
]
[
i
]
,
p
r
e
[
k
]
[
j
−
n
u
m
[
k
]
[
i
]
]
)
pre[i][j]=Max_{k}max(pre[k][j]+num[k][i],pre[k][j-num[k][i]])
pre[i][j]=Maxkmax(pre[k][j]+num[k][i],pre[k][j−num[k][i]])(就是分给哪边的情况)
第一问答案就是 M a x k m i n ( p r e [ t i m e ] [ k ] . k ) Max_{k}min(pre[time][k].k) Maxkmin(pre[time][k].k)
至于第二问,我们相当于钦点了一段区间
s
[
i
]
,
t
[
i
]
s[i],t[i]
s[i],t[i]必须选,设必须选
l
,
r
l,r
l,r的答案为
f
[
l
]
[
r
]
f[l][r]
f[l][r]
考虑类似于
p
r
e
pre
pre,处理出一个
s
u
f
[
i
]
[
j
]
suf[i][j]
suf[i][j]表示
i
i
i~
t
i
m
e
time
time的时间内给一边
j
j
j个另一边最多多少个
那我们可以直接枚举给左右一边分别多少个
则
f
[
l
]
[
r
]
=
M
a
x
x
,
y
m
i
n
(
p
r
e
[
l
]
[
x
]
+
n
u
m
[
l
]
[
r
]
+
s
u
f
[
r
]
[
y
]
,
x
+
y
)
f[l][r]=Max_{x,y}min(pre[l][x]+num[l][r]+suf[r][y],x+y)
f[l][r]=Maxx,ymin(pre[l][x]+num[l][r]+suf[r][y],x+y)
但有一个问题
我们处理出的
n
u
m
num
num表示的是全部在一段区间内的活动
而实际上有可能出现某一个活动,实际上在某一边里面
但由于时间跨越了我们的
l
,
r
l,r
l,r,没有被计算到内
所以实际上
a
n
s
i
=
M
a
x
l
,
r
f
[
l
]
[
r
]
ans_i=Max_{l,r}f[l][r]
ansi=Maxl,rf[l][r]
但这样复杂度是
O
(
n
4
)
O(n^4)
O(n4)的
考虑优化
发现在计算单个
l
,
r
l,r
l,r时,
x
x
x增大,
y
y
y总不会变大
因为
p
r
e
和
s
u
f
pre和suf
pre和suf都是单调递减的
而如果
p
r
e
pre
pre变小了,
s
u
f
suf
suf也随着变小肯定不会变的更优
如果
p
r
e
+
s
u
f
+
n
u
m
pre+suf+num
pre+suf+num为较小值的话这样就会变得更小,不优
如果
x
+
y
x+y
x+y为较小值的也会变得更小,也不优
所以枚举
x
x
x的时候,
y
y
y直接从大变小就可以了
复杂度
O
(
n
3
)
O(n^3)
O(n3)
#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<17|1;
inline char gc(){
static char ibuf[RLEN],*ib,*ob;
(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob)?EOF:*ib++;
}
inline int read(){
char ch=getchar();
int res=0,f=1;
while(!isdigit(ch))f^=(ch=='-'),ch=getchar();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
return res*f;
}
const int N=405;
int n,s[N],t[N],a[N],cnt,pre[N][N],suf[N][N],f[N][N],num[N][N];
inline void chemx(int &a,int b){
a=a>b?a:b;
}
inline void chemn(int &a,int b){
a=a>b?b:a;
}
#define calc(a,b) (min((a+b),(pre[l][a]+num[l][r]+suf[r][b])))
int main(){
n=read();
for(int i=1;i<=n;i++)s[i]=read(),a[++cnt]=s[i],t[i]=read()+s[i],a[++cnt]=t[i];
sort(a+1,a+cnt+1);
cnt=unique(a+1,a+cnt+1)-a-1;
for(int i=1;i<=n;i++){
s[i]=lower_bound(a+1,a+cnt+1,s[i])-a;
t[i]=lower_bound(a+1,a+cnt+1,t[i])-a;
for(int l=1;l<=s[i];l++)
for(int r=t[i];r<=cnt;r++)num[l][r]++;
}
for(int i=1;i<=cnt;i++)
for(int j=1;j<=n;j++)pre[i][j]=suf[i][j]=-1e9;
for(int i=1;i<=cnt;i++)
for(int j=0;j<=num[1][i];j++)
for(int k=1;k<=i;k++){
chemx(pre[i][j],pre[k][j]+num[k][i]);
if(j>=num[k][i])chemx(pre[i][j],pre[k][j-num[k][i]]);
}
for(int i=cnt;i;i--)
for(int j=0;j<=num[i][cnt];j++)
for(int k=cnt;k>=i;k--){
chemx(suf[i][j],suf[k][j]+num[i][k]);
if(j>=num[i][k])chemx(suf[i][j],max(suf[k][j]+num[i][k],suf[k][j-num[i][k]]));
}
for(int l=1;l<=cnt;l++){
for(int r=l;r<=cnt;r++){
for(int x=0,y=num[r][cnt];x<=num[1][l];x++){
while(y&&calc(x,y)<=calc(x,y-1))y--;
chemx(f[l][r],calc(x,y));
}
}
}
int ans=0;
for(int i=1;i<=cnt;i++)for(int j=1;j<=num[1][i];j++)chemx(ans,min(pre[i][j],j));
cout<<ans<<'\n';
for(int i=1;i<=n;i++){
int res=0;
for(int l=s[i];l;l--)
for(int r=t[i];r<=cnt;r++)
chemx(res,f[l][r]);
cout<<res<<'\n';
}
}