题目:
题意:
给出 n n n个活动的开始时间和持续时长,问在不限制必须举办哪一场和在有第 i ( i ∈ ( 1 − n ) ) i(i\in(1-n)) i(i∈(1−n))限制下,两个会场中举办较少的那一个的活动数最大
分析:
因为时间数值非常大,所以我们果断先离散化一遍。
为了方便表示,我们设
w
i
,
j
w_{i,j}
wi,j代表完全在
i
—
j
i—j
i—j这一段时间内举行的活动总数,
t
t
t表示最后一个活动在什么时候结束
设
f
i
,
j
f_{i,j}
fi,j表示在第
1
—
i
1—i
1—i的时间里,一个会场举办
j
j
j场活动,另一个会场最多举行多少
那么我们进行分类讨论得出方程:
1.
1.
1.如果在
i
i
i前已经举办了
j
j
j场,那么
w
k
,
i
(
k
∈
(
1
—
i
−
1
)
)
w_{k,i}(k\in(1—i-1))
wk,i(k∈(1—i−1))只能在另一个会场举行,也就说
f
i
,
j
=
f
k
,
j
+
w
k
,
i
f_{i,j}=f_{k,j}+w_{k,i}
fi,j=fk,j+wk,i
2.
2.
2.如果在
i
i
i前没有举办完
j
j
j场,那么
w
k
,
i
w_{k,i}
wk,i就只能在这一个会场举行,以保证这一个会场在
i
i
i时能举办
j
j
j场
f
i
,
j
=
f
k
,
j
−
w
k
,
j
f_{i,j}=f_{k,j-w_{k,j}}
fi,j=fk,j−wk,j
初始化则是
f
i
,
0
=
w
1
,
i
f_{i,0}=w_{1,i}
fi,0=w1,i
设
g
i
,
j
g_{i,j}
gi,j表示在
j
—
t
j—t
j—t的时间里,一个会场举办
j
j
j场活动,另一个会场最多举办多少
因为跟上面的
f
i
,
j
f_{i,j}
fi,j思路基本一致,所以这里就直接写出方程了
g
i
,
j
=
{
g
k
,
j
+
w
i
,
k
g
k
,
j
−
w
i
,
k
w
i
,
t
(
j
=
0
)
g_{i,j}=\left\{\begin{matrix} g_{k,j}+w_{i,k}\\ g_{k,j-w_{i,k}}\\ w_{i,t}\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ (j=0) \end{matrix}\right.
gi,j=⎩⎨⎧gk,j+wi,kgk,j−wi,kwi,t (j=0)
到了这一步,我们开始思考如何表达出答案了
第一问其实就相当于对后面有限制时的答案取
m
a
x
max
max,这样一来我们的重心就转移到如何做到必须选某个活动和如何表示出
a
n
s
i
ans_i
ansi
设
l
l
l表示当前一个会场举办的活动都在
l
l
l以后,
r
r
r表示当前该会场举办的活动都在
r
r
r以前
对于第一个如何,因为我们已经知道了每个活动的开始和结束时间,所以直接将
l
=
开
始
时
间
l=开始时间
l=开始时间,
r
=
结
束
时
间
r=结束时间
r=结束时间。因为
l
l
l是逐渐接近
1
1
1,
r
r
r是逐渐接近
t
t
t的,所以这样我们就做到了保证一个会场举办该活动
对于第二个如何,我们设
w
l
wl
wl表示在
l
l
l以前,该会场举办了多少活动,
w
r
wr
wr表示在
r
r
r以后,该会场举办了多少活动
那么就可以得到方程:
a
n
s
i
=
m
a
x
{
a
n
s
i
,
m
i
n
{
w
l
+
w
r
+
w
l
,
r
,
f
l
,
w
l
+
g
r
,
w
r
}
}
ans_i=max\{ans_i,min\{wl+wr+w_{l,r},f_{l,wl}+g_{r,wr}\}\}
ansi=max{ansi,min{wl+wr+wl,r,fl,wl+gr,wr}}
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#define LL long long
#define LZX IMS
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int a[205],b[205],begin[205],end[205],p[405],q[405],t=0;
int w[405][405],f[405][405],g[405][405],ans[205];
int main()
{
int n=read();
for(int i=1;i<=n;i++) {a[i]=read();b[i]=read()+a[i];p[++t]=a[i];p[++t]=b[i];}
sort(p+1,p+1+t);
q[1]=1;
for(int i=2;i<=t;i++) if(p[i]==p[i-1]) q[i]=q[i-1]; else q[i]=q[i-1]+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=t;j++)
{
if(p[j]==a[i]) begin[i]=q[j];
if(p[j]==b[i]) end[i]=q[j];
}
t=q[t];
for(int i=1;i<=t;i++)
for(int j=i+1;j<=t;j++)
for(int k=1;k<=n;k++)
if(begin[k]>=i&&end[k]<=j) w[i][j]++;
memset(f,-0x3f,sizeof(f));memset(g,-0x3f,sizeof(g));
for(int i=1;i<=t;i++)
for(int j=0;j<=min(n/2,w[1][i]);j++)
{
if(!j) f[i][0]=w[1][i];
for(int k=1;k<i;k++) f[i][j]=max(f[i][j],max(f[k][j]+w[k][i],f[k][j-w[k][i]]));
}
for(int i=t;i;i--)
for(int j=0;j<=min(n/2,w[i][t]);j++)
{
if(!j) g[i][0]=w[i][t];
for(int k=i+1;k<=t;k++) g[i][j]=max(g[i][j],max(g[k][j]+w[i][k],g[k][j-w[i][k]]));
}
for(int i=1;i<=n;i++)
{
for(int j=begin[i];j;j--)
for(int k=end[i];k<=t;k++)
{
for(int l=0;l<=w[1][j];l++)
{
for(int r=0;r<=w[k][t];r++)
{
ans[i]=max(ans[i],min(l+r+w[j][k],f[j][l]+g[k][r]));
if(g[k][r]<r) break;
}
if(f[j][l]<l) break;
}
if(w[1][j]+w[k][t]<ans[i]) break;
}
ans[0]=max(ans[0],ans[i]);
}
for(int i=0;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}