打砖块
Description
KXT是一个很无聊的小朋友,一天到晚都在打坐…
一天,被他发现了一个比打坐更无聊的事情——打砖块。很多块砖分布在一个mm的矩阵中,他可以消掉以他为左上角顶点的一个nn的矩阵里的所有砖块。
喜欢偷懒的他请来了你帮他计算可以消掉最多的砖块数(只能消一次)。
Input
第一行:用空格隔开的三个整数n、m、k。
接下来k行,每行2个用空格隔开的整数Xi、Yi,表示第i块砖在Xi行、Yi列的位置。
Output
为可以消掉最多的砖块数。
Sample Input
5 10 11
2 1
4 6
4 9
3 9
9 7
9 9
7 9
8 10
8 8
8 6
10 2
Sample Output
6
Hint
【数据范围】
n<=m; k<=m*m
60%:n<=70; m<=70; k<=4900
100%:n<=1000; m<=1000; k<=1000000;
思路
求最大n*n矩阵的和,与最大子矩阵之和差不多,
只是它的子矩阵一定是n乘n大小的。
先把每列的前缀和求出来,方便后面的计算:{
f
[
i
]
[
j
]
表
示
第
f[i][j]表示第
f[i][j]表示第i
行
第
行第
行第j
列
有
砖
块
;
列有砖块;
列有砖块;
f
[
i
]
[
j
]
+
=
f
[
i
−
1
]
[
j
]
f[i][j]+=f[i-1][j]
f[i][j]+=f[i−1][j]
1
<
=
i
,
j
<
=
m
1<=i,j<=m
1<=i,j<=m
}
DP:
i
,
j
i,j
i,j枚举左上角顶点,
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示第
i
i
i行第
j
j
j列的前缀和,
l
l
l为当前n乘n矩阵的砖块数
l
=
0
l=0
l=0
l
+
=
f
[
i
+
n
−
1
]
[
k
]
−
f
[
i
−
1
]
[
k
]
l+=f[i+n-1][k]-f[i-1][k]
l+=f[i+n−1][k]−f[i−1][k]
1
<
=
i
,
j
<
=
m
−
n
+
1
;
j
<
=
k
<
=
n
+
j
+
1
1<=i,j<=m-n+1;j<=k<=n+j+1
1<=i,j<=m−n+1;j<=k<=n+j+1
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstdlib>
using namespace std;
int n,m,f[1001][1001],ans,d,p,q,l;
void in(){
scanf("%d%d%d",&n,&m,&d);
for(int i=1;i<=d;i++){
scanf("%d%d",&p,&q);
f[p][q]++;//记录砖块位置
}for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
f[i][j]+=f[i-1][j];//每列前缀和
}
}
}void DP(){n
for(int i=1;i<=m-n+1;i++){//<=m-n+1即可,最多到这里
for(int j=1;j<=m-n+1;j++){
l=0;//要清 0
for(int k=j;k<=n+j-1;k++){
l+=f[i+n-1][k]-f[i-1][k];//状态转移方程
ans=max(l,ans);//记录最大答案
}
}
}
}
int main(){
in();
DP();
printf("%d",ans);
}