题目描述
小A踏上了AK这场新生赛的旅程。但对方太狡猾,将小A传送到了一个不知名的地方。经过探查,小A发现了一座很大的迷宫。这座迷宫从上方看竟然是正方形的,而且内部被分为了1个同等大小房间,而狡猾的敌人则隐藏在某些房间中,准备偷袭小A.
幸好小A提前发现了对方的阴谋,准备解决所有的敌人。但敌人太多了,小A准备使用高级魔法---“这题我会”。这个魔法的作用范围是正好是一个矩形,能够覆盖W∗H个房间(注意:W∗H与H∗W是不同的,如:2 * 3与3 * 2是两种魔法),处于该范围内的敌人将会被魔法消灭魔法的边界必须与房间的墙壁重合,否则狡猾的敌人会躲在墙边,从而躲开此次攻击。小A只能发动一次该魔法,他希望魔法发动时能攻击到更多的敌人。小A选择寻求你的帮助,他告诉你了n个敌人的位置,你能告诉他,发动魔法最多能消灭多少个敌人吗?
例如:小A魔法的范围是3*2,他共探查到了5个敌人,位置如下,他最多可以消灭4个敌人。
输入
第一行包含3个整数n, W, H(1<= n <= 100, 1<= W, H<= 1000)。代表共有n个敌人,魔法的打击范围是W*H。
接下来n行,每行包含两个整数x_i, y_i(1<= x_i, y_i <= 1000), 代表第i个敌人位于坐标(xi, yi)的房间。保证每个房间最多只有一个敌人。
输出
输出一个整数。代表小A发动魔法,最多消灭的敌人的数量。
样例输入 Copy
5 3 2 1 1 2 1 3 1 4 1 4 2
样例输出 Copy
4
思路:前缀与差分,把有敌人的点都设为1;然后从右下角的x2y2分别等于wh开始枚举到1000,根据边的关系算出x1y1,然后用公式算出x1y1x2y2的矩形内所有数的和,即为所求的最大敌人数,一般方法是需要再开一个s【n】【n】,但是可能会导致内存超限,所以直接根据公式把他自己变成自己的前缀和就行了
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,w,h,ans;
int g[1005][1005];
int main(){
scanf("%d%d%d",&n,&w,&h);
while(n--){
int x,y;
scanf("%d%d",&x,&y);
g[x][y]++;
}
for(int i=1;i<=1000;i++){
for(int j=1;j<=1000;j++){
g[i][j]+=g[i-1][j]+g[i][j-1]-g[i-1][j-1];
}
}
for(int i=w;i<=1000;i++){
for(int j=h;j<=1000;j++){
int x1=i-w;
int y1=j-h;
ans=max(ans,g[i][j]-g[x1][j]-g[i][y1]+g[x1][y1]);
}
}
printf("%d",ans);
return 0;
}