NBUT 1618 投放炸弹(树状数组)

  • [1618] 投放炸弹

  • 时间限制: 1000 ms 内存限制: 65535 K
  • 问题描述
  • 我们定义一个炸弹能炸毁的地方要求曼哈顿距离小于等于某个值。
    曼哈顿距离——两点在南北方向上的距离加上在东西方向上的距离,即d(i,j)=|xi-xj|+|yi-yj|。-来自百度百科
    现在给出一个n*m的平面图,'.'表示无人区,'*'表示居民区。炸弹只能投放在无人区,炸弹能炸毁曼哈顿距离小于等于x的所有居民区,现在你要来投放这个炸弹,请输出炸弹最多能炸毁的居民区个数。
  • 输入
  • 多组输入,每组第一行n,m,x。
    接下来输入n行,每行m个字符,字符只有'.'和'*'。
    数据范围:1<=n,m<=200,1<=x<=1e9
  • 输出
  • 每组输出一行,最多可以炸毁的居民区个数。
  • 样例输入
  • 4 5 1
    ..*..
    **.**
    ..*..
    .....
    2 3 4
    ***
    ***
  • 样例输出
  • 4
    0

 

题目链接:NBUT 1618

大一那会儿留下来的题目,最近想学KDtree突然想起来这题……很那啥的一道题,佩服作者的YY能力,实际上题目中炸弹范围是一个菱形,如果忽略地图边界,还是一个完全对称的菱形,DFS的话T了很多发,这题如果仔细想想是可以用二维树状数组做的,T[i][j]维护第i行前j个格子中含有居民点的前缀和,菱形内的居民区个数可以从上到下一行一行地求出来,当然这题有个小坑就是范围可以很大,那么根据题目实际地图大小缩小到实际可以使用的范围就好了。求和的时候个别边界出现负数处理一下即可

代码:

#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <sstream>
#include <numeric>
#include <cstring>
#include <bitset>
#include <string>
#include <deque>
#include <stack>
#include <cmath>
#include <queue>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define LC(x) (x<<1)
#define RC(x) ((x<<1)+1)
#define MID(x,y) ((x+y)>>1)
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define FAST_IO ios::sync_with_stdio(false);cin.tie(0);
typedef pair<int, int> pii;
typedef long long LL;
const double PI = acos(-1.0);
const int N = 210;
int T[N][N];
char s[N][N];
int n, m;

void init()
{
	CLR(T, 0);
}
void add(int h, int k, int v)
{
	while (k < N)
	{
		T[h][k] += v;
		k += (k & -k);
	}
}
int getsum(int h, int k)
{
	if (k <= 0)
		return 0;
	int ret = 0;
	if (k > m)
		k = m;
	while (k)
	{
		ret += T[h][k];
		k -= (k & -k);
	}
	return ret;
}
int main(void)
{
	int k, i, j;
	while (~scanf("%d%d%d", &n, &m, &k))
	{
		init();
		for (i = 1; i <= n; ++i)
		{
			scanf("%s", s[i] + 1);
			for (j = 1; j <= m; ++j)
			{
				if (s[i][j] == '*')
					add(i, j, 1);
			}
		}
		int ans = 0;
		k = min(k, max(n, m));
		for (i = 1; i <= n; ++i)
		{
			for (j = 1; j <= m; ++j)
			{
				if (s[i][j] == '.')
				{
					int temp = getsum(i, j + k) - getsum(i, j - k - 1);
					for (int kk = 1; kk <= k; ++kk)
					{
						int up = i - kk, down = i + kk;
						if (up >= 1)
							temp += getsum(up, j + k - kk) - getsum(up, j - k - 1 + kk);
						if (down <= n)
							temp += getsum(down, j + k - kk) - getsum(down, j - k - 1 + kk);
					}
					if (temp > ans)
						ans = temp;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}
posted @ 2017-05-19 13:51  Blackops  阅读(190)  评论(0编辑  收藏  举报