原题链接
题意:有若干行,每行分为若干段,每段可以选定一个位置放入一个1,求放完所有1以后每列1个数的平方数之和的最大值
题解:题目后效性很强,考虑DP,设范围
i
i
i ~
j
j
j的最大值为
D
P
[
i
]
[
j
]
DP[i][j]
DP[i][j],考虑合并两个区间,感觉没有思路,于是取出一条,再与两边区间合并,显然根据贪心思路,这一条尽可能全选,但会存在后效性,即两边区间该段已有选择位置置1。所以添加一个限制,令
D
P
[
i
]
[
j
]
DP[i][j]
DP[i][j]中能置1的段都要包括在
i
i
i ~
j
j
j内,这样便不会和新增的一条冲突,如此区间DP的转移方程便可得出
D
P
[
i
]
[
j
]
=
m
a
x
(
D
P
[
i
]
[
j
]
,
D
P
[
i
]
[
k
−
1
]
+
D
P
[
k
+
1
]
[
j
]
+
(
∑
x
=
1
x
<
=
n
(
第
x
行
k
列
所
在
的
段
在
i
到
j
中
)
)
DP[i][j]=max(DP[i][j],DP[i][k-1]+DP[k+1][j]+(\sum_{x=1}^{x<=n}(第x行k列所在的段在i到j中))
DP[i][j]=max(DP[i][j],DP[i][k−1]+DP[k+1][j]+(∑x=1x<=n(第x行k列所在的段在i到j中))
其中
x
x
x行
k
k
k列所在的段要预处理
代码如下
#include<bits/stdc++.h>
using namespace std;
int n,m;
int dp[111][111];
int num;
int l[110][110],r[110][110];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
int tmp,ll,rr;
scanf("%d",&tmp);
for(int j=1;j<=tmp;j++)
{
scanf("%d%d",&ll,&rr);
for(int j=ll;j<=rr;j++)
{
l[i][j]=ll;
r[i][j]=rr;
}
}
}
for(int len=1;len<=m;len++)
{
for(int i=1;i+len-1<=m;i++)
{
int j=i+len-1;
for(int k=i;k<=j;k++)
{
int cnt=0;
for(int x=1;x<=n;x++) if(i<=l[x][k]&&r[x][k]<=j) cnt++;
dp[i][j]=max(dp[i][k-1]+dp[k+1][j]+cnt*cnt,dp[i][j]);
}
}
}
printf("%d\n",dp[1][m]);
}