版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/er111er/article/details/79117064
无线网络发射器选址 题解
题目大意分析
在一个129*129的矩阵中,每个点都有一个权值,给定一个d,让你选择一个点(x,y),令(x-d,y-d)到(x+d,y+d)中的权值之和最大,并求出使权值之和最大的方案数有多少。
思路
暴力做法
暴力做法是小学生水平,只需要从(1,1)到(129,129)(为了方便储存把横纵坐标都+1)枚举这个点,然后由(x-d,y-d)到(x+d,y+d)枚举求出权值之和,然后找出最大的权值之和。之后再这样枚举一次,找出有多少个点对应覆盖的区域的权值之和为这个最大值,这就是方案数。
分析复杂度,会发现这是一个
基于暴力的优化
考虑原来求一个子矩阵权值之和的过程,时间复杂度为
二维前缀和
一维前缀和你肯定知道,设
二维前缀和也类似,设
先求解sum的递推式,观察下图。
可以看出
类似的,求某一个子矩阵的和如下图(画得很丑,别介意)
欲求(x1,y1)至(x2,y2)的和,就是
这样就能够在
代码(C++):
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
const int N = 137;
typedef long long ll;
int d, n, x, y, xx, yy;
ll a[N][N], sum[N][N], k, mxans = 0, mxcnt; //不开long long稳爆炸
inline int read() //读入优化
{
int x = 0, f = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0';
return f ? -x : x;
}
inline ll min(ll a, ll b) { return a < b ? a : b; } //自定义max&&min函数加速
inline ll max(ll a, ll b) { return a > b ? a : b; }
int main()
{
d = read(), n = read();
for (int i = 1; i <= n; i++)
x = read(), y = read(), k = read(),
a[x + 1][y + 1] = k; //方便起见+1
for (int i = 1; i <= 129; i++)
for (int j = 1; j <= 129; j++)
sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j]; //预处理sum数组
for (int i = 1; i <= 129; i++)
for (int j = 1; j <= 129; j++)
x = max(i - d, 1), y = max(j - d, 1), //防止越界
xx = min(i + d, 129), yy = min(j + d, 129), //防止越界
mxans = max(mxans, sum[xx][yy] - sum[x - 1][yy] - sum[xx][y - 1] + sum[x - 1][y - 1]); //求出最大的值
for (int i = 1; i <= 129; i++)
for (int j = 1; j <= 129; j++)
{
x = max(i - d, 1), y = max(j - d, 1); //防止越界
xx = min(i + d, 129), yy = min(j + d, 129); //防止越界
if (sum[xx][yy] - sum[x - 1][yy] - sum[xx][y - 1] + sum[x - 1][y - 1] == mxans) mxcnt++; //如果等于最大的值就多一种方案
}
printf("%lld %lld\n", mxcnt, mxans);
return 0;
}