原题:https://www.luogu.org/problem/show?pid=2038
数据量小得出奇,直接四重循环暴力就能过。
这道题的重点其实不是暴力,而是边界。注意到无线网络发射器能放到边缘处,但那样覆盖到地图的范围就不是一个正方形了。。
曾经想过预处理一下每个子矩阵的公共场所的总数量,然后在这个预处理的答案中再找最大值和有最大值的个数。但我后来发现完全不必要,而且不好写。
边界的处理。C++不能像pascal那样让数组下标变为负,所以我使用了“地图平移”操作。注意到数据范围1≤d≤20,即覆盖范围的边长的一半最大到20,那么,在读入的时候把所有坐标都+20,遍历时的坐标也同样的+20,地图边长最大128,那么遍历的长度就基本确定了:20~148.
刚才说到四重循环,前两重循环枚举放置点,后两重循环以这个枚举点为中心直接计算和,然后维护最大值就好。
如果你不喜欢这么做,可以按照我刚才的做法, 预处理处一个数组,这样可以只循环两层。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define maxn 233 5 using namespace std; 6 int d,n,x,y,k; 7 int a[maxn][maxn]; 8 const int edge = 20; 9 const int maxmap = 128; 10 int maxv; 11 int summat; 12 int cnt = 1; 13 int main(){ 14 cin >> d; 15 cin >> n; 16 for (int i=1;i<=n;i++){ 17 cin >> x >> y; 18 cin >> a[x+edge][y+edge]; 19 } 20 for (int i=edge;i<=edge+maxmap;i++) 21 for (int j=edge;j<=edge+maxmap;j++){ 22 for (int p=i-d;p<=i+d;p++) 23 for (int q=j-d;q<=j+d;q++) 24 summat+=a[p][q]; 25 if (maxv == summat) 26 cnt++; 27 else if(maxv<summat) 28 cnt = 1; 29 maxv = max(summat,maxv); 30 summat = 0; 31 } 32 cout << cnt << " " << maxv << endl; 33 return 0; 34 }