【2014年东莞市小学】打砖块

本题目来源于JZOJ的考试
这里是友情链接

下面进入正题

题目描述

K X T KXT KXT是一个很无聊的小朋友,一天到晚都在打坐…
一天,被他发现了一个比打坐更无聊的事情——打砖块。很多块砖分布在一个 m ∗ m m*m mm的矩阵中,他可以消掉以他为左上角顶点的一个 n ∗ n n*n nn的矩阵里的所有砖块。
喜欢偷懒的他请来了你帮他计算可以消掉最多的砖块数(只能消一次)。

输入

输入文件 b r i c k . i n brick.in brick.in中,第一行:用空格隔开的三个整数 n 、 m 、 k n、m、k nmk

接下来 k k k行,每行 2 2 2个用空格隔开的整数 X i 、 Y i , Xi、Yi, XiYi表示第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就到这里了,楼下隐形字,欢迎扫一扫查看↓。。。

哥哥姐姐们,写的辣么辛苦,不点赞,关个注再走嘛!?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值