BZOJ传送门
题目描述
Byteasar 组建了一支舰队!他们现在正在海洋上航行着。
海洋可以抽象成一张
n
×
m
n×m
n×m 的网格图,其中有些位置是 .
,表示这一格是海水,可以通过;有些位置是 #
,表示这一格是礁石,不可以通过;有些位置是 o
,表示这一格目前有一艘舰,且舰离开这一格之后,这一格将变为 .
。
这些 o
表示 Byteasar 的舰队,他们每天可以往上下左右中的一个方向移动一格,但不能有任何一艘舰驶出地图。特别地,Byteasar 对阵形有所研究,所以他不希望在航行的过程中改变阵形,即任何时刻任何两艘舰的相对位置都不能发生变化。
Byteasar 的舰队可以航行无限长的时间,每当一艘舰经过某个格子的时候,这个格子海底的矿藏都将被 Byteasar 获得。请写一个程序,帮助 Byteasar 计算他最多可以获得多少个格子海底的矿藏?
输入输出格式
输入格式
第一行包含两个正整数 n , m n,m n,m,分别表示地图的长和宽。
接下来
n
n
n 行,每行有
m
m
m 个字符,每个字符只能是 .
、#
、o
中的一个。
输入数据保证至少有一个 o
。
输出格式
输出一行一个整数,即可以被经过的格子数的最大值。
输入输出样例
输入样例#1:
4 5....#.o#.o.o..o..o..
4 5
....#
.o#.o
.o..o
..o..
输出样例#1:
12
数据范围
解题分析
如果我们做过这道题就会感觉到其实这道题是道套路题了… 我们把二位的图压成一维后, 可以通过同样的处理得到左上角合法的位置数量, 进而 B F S BFS BFS得到可行的相对位置。
最后就是算到达过的次数了。 实质上就是在某一个左上角合法的位置可以利用相对位置到达这个点, 也是一次 F F T FFT FFT,最后值 > 1 >1 >1即可确定。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MX 705
#define db double
using std::max; using std::min;
const db PI = std::acos(-1.0);
struct Cood {int x, y;}; std::queue <Cood> que;
struct Complex {db im, re;} a[MX * MX * 4], b[MX * MX * 4];
IN Complex operator * (const Complex &x, const Complex &y) {return {x.im * y.re + x.re * y.im, x.re * y.re - x.im * y.im};}
IN Complex operator + (const Complex &x, const Complex &y) {return {x.im + y.im, x.re + y.re};}
IN Complex operator - (const Complex &x, const Complex &y) {return {x.im - y.im, x.re - y.re};}
char mp[MX][MX];
bool vis[MX][MX];
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int mxx = 0, mnx = MX, mxy = 0, mny = MX, siz, n, m, tot, lg, delx, dely, ans;
int rev[MX * MX * 4];
void FFT(Complex *dat, const int &typ)
{
for (R int i = 1; i < tot; ++i) if(rev[i] > i) std::swap(dat[rev[i]], dat[i]);
R int cur, now, seg, bd, step; Complex buf1, buf2, deal, base;
for (seg = 1; seg < tot; seg <<= 1)
{
base = {std::sin(PI / seg) * typ, std::cos(PI / seg)}; step = seg << 1;
for (now = 0; now < tot; now += step)
{
bd = now + seg; deal = {0, 1};
for (cur = now; cur < bd; ++cur, deal = deal * base)
{
buf1 = dat[cur], buf2 = dat[cur + seg] * deal;
dat[cur] = buf1 + buf2, dat[cur + seg] = buf1 - buf2;
}
}
}
}
void BFS(R int x, R int y)
{
Cood now;
que.push({x, y}); vis[x][y] = false;
W (!que.empty())
{
now = que.front(); que.pop(); x = now.x, y = now.y;
a[(x - 1) * m + y - 1] = {0, 1};
for (R int i = 0; i < 4; ++i)
if(vis[x + dir[i][0]][y + dir[i][1]])
que.push({x + dir[i][0], y + dir[i][1]}), vis[x + dir[i][0]][y + dir[i][1]] = false;
}
}
int main(void)
{
scanf("%d%d", &n, &m); siz = n * m;
for (R int i = 1; i <= n; ++i) scanf("%s", mp[i] + 1);
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
if(mp[i][j] == 'o')
{
mxx = max(mxx, j); mnx = min(mnx, j);
mxy = max(mxy, i); mny = min(mny, i);
}
else if(mp[i][j] == '#') a[siz - (i - 1) * m - j] = {0, 1};
delx = mxx - mnx, dely = mxy - mny;
for (R int i = 1; i <= n; ++i) for (R int j = 1; j <= m; ++j) if(mp[i][j] == 'o')
b[(i - mny) * m + j - mnx] = {0, 1};
for (tot = 1; tot <= n * m * 2; tot <<= 1, ++lg);
for (R int i = 1; i < tot; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
FFT(a, 1), FFT(b, 1);
for (R int i = 0; i < tot; ++i) a[i] = a[i] * b[i];
FFT(a, -1);
int bdx = m - delx, bdy = n - dely;
for (R int i = 1; i <= bdy; ++i) for (R int j = 1; j <= bdx; ++j)
if(fabs(a[siz - (i - 1) * m - j].re) < 0.5) vis[i][j] = true;
for (R int i = 0; i < tot; ++i) a[i] = {0, 0};
BFS(mny, mnx);
FFT(a, 1);
for (R int i = 0; i < tot; ++i) a[i] = a[i] * b[i];
FFT(a, -1);
for (R int i = 0; i < siz; ++i) if(a[i].re > 0.5) ++ans;
printf("%d", ans);
}