本题目来源于JZOJ的考试
这里是友情链接
下面进入正题
题目描述
K
X
T
KXT
KXT是一个很无聊的小朋友,一天到晚都在打坐…
一天,被他发现了一个比打坐更无聊的事情——打砖块。很多块砖分布在一个
m
∗
m
m*m
m∗m的矩阵中,他可以消掉以他为左上角顶点的一个
n
∗
n
n*n
n∗n的矩阵里的所有砖块。
喜欢偷懒的他请来了你帮他计算可以消掉最多的砖块数(只能消一次)。
输入
输入文件 b r i c k . i n brick.in brick.in中,第一行:用空格隔开的三个整数 n 、 m 、 k n、m、k n、m、k。
接下来 k k k行,每行 2 2 2个用空格隔开的整数 X i 、 Y i , Xi、Yi, Xi、Yi,表示第i块砖在 X i Xi Xi行、 Y i Yi Yi列的位置。
输出
输出文件 b r i c k . o u t brick.out brick.out中,为可以消掉最多的砖块数。
样例输入
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
样例输出
6
数据范围限制
n<=m; k<=m*m
60%:n<=70; m<=70; k<=4900
100%:n<=1000; m<=1000; k<=1000000;
来,先看看这道题样例的图(手打的,感觉极差。。)↓
这道题一拿到手,我就感觉。。。应该是用深搜(或者宽搜)做啊!于是我就瞎搞了半天,一个矩阵套矩阵的东西,乍一看:那必须超时啊!就算耗尽所有卡常方法也会
T
L
E
TLE
TLE啊!于是乎,我想到了二维前缀和(如果您老人家不知道前缀和什么的,可以看一看这个,讲得还是满详细的)
其实只要想到二维前缀和,这道题就变得没那么复杂了,那就直接上代码吧。。
#pragma GCC optimize(2)//嘿嘿,偷偷吸点氧气
#include<bits/stdc++.h>//Van能头
using namespace std;
long long dp[1001][1001],ans;//定大一些似乎并没有什么坏处
int main(){
freopen("brick.in","r",stdin);
freopen("brick.out","w",stdout);//文件操作
int n,m,k,x,y;
cin>>n>>m>>k;
//问我为什么加了"register",这是一种卡常方法把变量放到CPU寄存器中,适用于一些使用频繁的变量,我一般都用在for循环里面,优化效果还是很好的
for(register int i=1;i<=k;i++){
cin>>x>>y;
dp[x][y]++;//做个标记,存一下
}
if(m==n){//这里是特判,其实可有可无,但是能让程序快一些
cout<<k<<endl;
return 0;
}
//最重要的部分来了!
for(register int i=1;i<=m;i++)
for(register int j=1;j<=m;j++)
dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+dp[i][j];//这里是二维前缀和的操作,重点!
for(register int i=1;i<=m-n+1;i++)
for(register int j=1;j<=m-n+1;j++)
ans=max(ans,dp[i-1][j-1]-dp[i+n-1][j-1]-dp[i-1][j+n-1]+dp[i+n-1][j+n-1]);//dp的状态转移方程
cout<<ans<<endl;
return 0;//完美结束
}
嗯这篇blog就到这里了,楼下隐形字,欢迎扫一扫查看↓。。。