题目:
题意:
有
m
m
m个形如
{
a
i
,
b
i
,
c
i
}
\{a_i,b_i,c_i\}
{ai,bi,ci}的三元组,表示在
a
i
∼
b
i
a_i\sim b_i
ai∼bi的区间内,
x
m
i
n
x_{min}
xmin如果
<
=
c
i
<=c_i
<=ci,则此询问有
x
m
i
n
x_{min}
xmin的贡献
问如何安排
x
i
x_i
xi的大小能使得最后答案最大
分析:
首先我们可以发现,
x
i
x_i
xi一定是某个
c
i
c_i
ci,因为如果
c
i
1
<
x
i
<
c
i
2
c_{i1}<x_i<c_{i2}
ci1<xi<ci2,那么对于
i
1
i_1
i1并不会产生更多的贡献,而
i
2
i_2
i2虽然产生了,但显然比
x
i
=
c
i
2
x_i=c_{i2}
xi=ci2的贡献小
据此,我们阔以考虑将
c
c
c离散化处理
我们需要记录的量有区间
(
l
,
r
)
(l,r)
(l,r)、
x
m
i
n
x_{min}
xmin、
x
m
i
n
x_{min}
xmin的位置
那么设
f
l
,
r
,
w
f_{l,r,w}
fl,r,w表示对于所有
l
<
=
a
i
&
b
i
<
=
r
l<=a_i\&b_i<=r
l<=ai&bi<=r的询问,当
x
m
i
n
=
w
x_{min}=w
xmin=w时取得最大贡献,
k
k
k为
l
∼
r
l\sim r
l∼r间的某个位置,表示
w
w
w的位置
同时统计下
w
w
w会对哪些询问产生贡献,显然需要满足
l
<
=
a
i
<
=
k
<
=
b
i
<
=
r
&
c
i
>
=
w
l<=a_i<=k<=b_i<=r\&c_i>=w
l<=ai<=k<=bi<=r&ci>=w,设这样的询问有
c
n
t
w
cnt_w
cntw个
有
f
l
,
r
,
w
=
w
∗
c
n
t
w
+
m
a
x
{
f
l
,
k
−
1
,
h
}
+
m
a
x
{
f
k
+
1
,
r
,
h
}
∣
h
>
=
w
f_{l,r,w}=w*cnt_w+max\{f_{l,k-1,h}\}+max\{f_{k+1,r,h}\}\ |\ h>=w
fl,r,w=w∗cntw+max{fl,k−1,h}+max{fk+1,r,h} ∣ h>=w
直接转移复杂度为
O
(
n
3
m
)
O(n^3m)
O(n3m)
但注意到是取最大值,我们可以对每个
f
l
,
r
f_{l,r}
fl,r搞一个后缀最大值,转移的时候直接调用
此时复杂度来到
O
(
n
2
m
)
O(n^2m)
O(n2m),可以解决此题
对于每个
x
i
x_i
xi的值,我们只需要记录下每个最大值是从
w
w
w为哪个值转移来的
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#define LL long long
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[4005],b[4005],c[4005],cnt[4005],bc[4005];
int n,m,t;
void S(int l,int r,int k)
{
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=m;i++)
if(l<=a[i]&&a[i]<=k&&k<=b[i]&&b[i]<=r)
cnt[c[i]]++;
for(int i=t;i;i--) cnt[i]+=cnt[i+1];
return;
}
int f[55][55][4005],kf[55][55][4005],g[55][55][4005],kg[55][55][4005];
void get(int l,int r,int w)
{
if(!l||!r||l>r) return;
int k=kf[l][r][w];
get(l,k-1,kg[l][k-1][w]);
printf("%d ",bc[w]);
get(k+1,r,kg[k+1][r][w]);
return;
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;i++) a[i]=read(),b[i]=read(),bc[i]=c[i]=read();
sort(bc+1,bc+1+m);
t=unique(bc+1,bc+1+m)-bc-1;
for(int i=1;i<=m;i++) c[i]=lower_bound(bc+1,bc+1+t,c[i])-bc;
for(int len=1;len<=n;len++)
for(int l=1;l<=n;l++)
{
int r=l+len-1;
if(r>n) continue;
for(int k=l;k<=r;k++)
{
S(l,r,k);
for(int w=1;w<=t;w++)
if(f[l][r][w]<g[l][k-1][w]+g[k+1][r][w]+bc[w]*cnt[w]||!f[l][r][w])
f[l][r][w]=g[l][k-1][w]+g[k+1][r][w]+bc[w]*cnt[w],kf[l][r][w]=k;
}
for(int w=t;w;w--)
if(g[l][r][w+1]>f[l][r][w]) g[l][r][w]=g[l][r][w+1],kg[l][r][w]=kg[l][r][w+1];
else g[l][r][w]=f[l][r][w],kg[l][r][w]=w;
}
printf("%d\n",g[1][n][1]);
get(1,n,kg[1][n][1]);
return 0;
}