Problem

Description

Lavender、Caryophyllus、Jasmine、Dianthus现在在玩一款名叫“赛艇”的游戏。

这个游戏的规则是这样的:

  1. 玩家自由组成两队,一个人当赛艇的艇长,另一个人当侦察兵;
  2. 每次游戏开始时,双方均拥有由系统生成的某张地图,该地图以01矩阵的形式表示,1表示有障碍物,无法通行,0表示水域空旷,可以通行;
  3. 第一回合,双方的赛艇艇长都要在地图上指定一个出发点,该出发点不能是障碍物,也就是只能为0
  4. 在每个回合中,艇长可以指挥自己的赛艇向上/下/左/右四个方向的某一方向的空旷水域移动一个单位的距离,也就是说只能移向四个方向上的某个0上(当然,不能移动出地图之外);在该操作完成之后,必须向对方说出自己在该回合移动的方向
  5. 双方的侦察兵负责记录每一回合对方赛艇的移动方向,并负责推断此时对方赛艇可能的位置;如果某方的侦察兵推测出对方赛艇此时的精确位置,那么可以向其发射导弹,该侦察兵所在的一方胜利;

现在,Jasmine记录了一些对方赛艇的路径,她想确定一下此时对方所有可能的位置共有几种。由于她不是很擅长计算,所以这个任务就交给你了。

Input Format

输入第一行包含三个正整数 \(n\),\(m\),\(k\),分别表示地图为 \(n\) 行 \(m\) 列,当前游戏已经进行了 \(k\) 轮。

输入第二行到第 \(n+1\) 行为一个 \(n\) 行 \(m\) 列的 01 矩阵,无任何分隔符号,表示地图的具体信息,具体含义如上所示。

输入的最后一行为一个长度为 \(k\) 的字符串 \(s\),仅由字母 wasd 构成,从前往后第 \(i\) 个字符 \(s_i\) 表示对方在第 \(i\) 轮中,对方赛艇向上/左/下/右移动一个单位距离。

Output Format

输出一行一个正整数,表示在第 \(k\) 轮游戏回合的时候,对方赛艇可能的位置的种数。对于所有输入数据,保证有合法解

Sample

Input

5 6 5
000000
001001
000100
001000
000001
dwdaa

Output

4

Explanation

Explanation for Input

上图显示了路径序列可视化之后的结果,下图用蓝色标出了此时对方赛艇可能的位置。

Range

\(2\le n,m \le 1500, 1\le k\le 5\times 10^6\)

Algorithm

多项式

Mentality

套路题。

我们将走过的路径可视化,表示为一个矩阵。矩阵中为 \(1\) 的位置表示走到过,反之走不到。

那么这道题就相当于我们能够找到多少个点,满足将矩阵的左上角与这个点对齐后,矩阵中的 \(1\) 与原图中的 \(1\) 不重合。

考虑将矩阵的列数补齐至 \(m\) 列,然后将原图和矩阵分别拆成一维的数组 \(f,g\),即第一行后面接上第二行,第二行后面接上第三行这样的。

然后将矩阵拆出的 \(g\) 数组翻转得到 \(g'\),和 \(f\) 进行卷积得到 \(F\) 。

若 \(f\) 的长度为 \(a\),\(g\) 的长度为 \(b\),不难发现,对于一个满足要求的,原图中可以对齐矩阵左上角而合法的点 \((x,y)\) ,若其在 \(f\) 中对应第 \(i\) 个位置,矩阵的 \((0,0)\) 在 \(g\) 中对应 \(0\),在 \(g'\) 中对应 \(b-1\) ,那么以 \((x,y)\) 为左上角和矩阵相叠的结果将存在于 \(F\) 的第 \(i+b-1\) 中。

我们只需要对那些合法的,有足够空间去作为左上角叠下这个矩阵的点,统计它们在 \(F\) 中对应结果即可。

答案即为这些结果中 \(0\) 的个数。

Code

#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
#define LL long long
#define go(x, i, v) for (int i = hd[x], v = to[i]; i; v = to[i = nx[i]])
#define inline __inline__ __attribute__((always_inline))
LL read() {
long long x = 0, w = 1;
char ch = getchar();
while (!isdigit(ch)) w = ch == '-' ? -1 : 1, ch = getchar();
while (isdigit(ch)) {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar();
}
return x * w;
}
const int Max_n = 1505, Max_l = 5e6 + 5, mod = 998244353, G = 3;
int n, m, K, ans, dx[5] = {0, -1, 1, 0, 0}, dy[5] = {0, 0, 0, -1, 1};
int lim, bit, rev[Max_l], f[Max_l], g[Max_l];
int s[Max_l], a[Max_n][Max_n];
char S[Max_l];
int ksm(int a, int b) {
int res = 1;
for (; b; b >>= 1, a = 1ll * a * a % mod)
if (b & 1) res = 1ll * res * a % mod;
return res;
}
namespace NTT {
void dft(int *f, bool t) {
for (int i = 0; i < lim; i++)
if (rev[i] > i) swap(f[i], f[rev[i]]);
for (int len = 1; len < lim; len <<= 1) {
int Wn = ksm(G, (mod - 1) / (len << 1));
if (!t) Wn = ksm(Wn, mod - 2);
for (int i = 0; i < lim; i += len << 1) {
int Wnk = 1;
for (int k = i; k < i + len; k++, Wnk = 1ll * Wnk * Wn % mod) {
int x = f[k], y = 1ll * Wnk * f[k + len] % mod;
f[k] = (x + y) % mod, f[k + len] = (x - y + mod) % mod;
}
}
}
}
} // namespace NTT
void ntt(int *f, int *g) {
NTT::dft(f, 0), NTT::dft(g, 0);
for (int i = 0; i < lim; i++) f[i] = 1ll * f[i] * g[i] % mod;
NTT::dft(f, 1);
int Inv = ksm(lim, mod - 2);
for (int i = 0; i < lim; i++) f[i] = 1ll * f[i] * Inv % mod;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("5447.in", "r", stdin);
freopen("5447.out", "w", stdout);
#endif
n = read(), m = read(), K = read();
for (int i = 0; i < n; i++) {
scanf("%s", S);
for (int j = 0; j < m; j++) f[i * m + j] = S[j] == '1';
}
scanf("%s", S + 1);
for (int i = 1; i <= K; i++) {
if (S[i] == 'w') s[i] = 1;
if (S[i] == 's') s[i] = 2;
if (S[i] == 'a') s[i] = 3;
if (S[i] == 'd') s[i] = 4;
}
int sx = 0, sy = 0, l = 0, r = 0, u = 0, d = 0;
for (int i = 1; i <= K; i++) {
sx += dx[s[i]], sy += dy[s[i]];
l = min(l, sy), r = max(r, sy), u = min(u, sx), d = max(d, sx);
}
r -= l, sy = -l, l = 0, d -= u, sx = -u, u = 0;
a[sx][sy] = 1;
for (int i = 1; i <= K; i++) a[sx += dx[s[i]]][sy += dy[s[i]]] = 1;
for (int i = 0; i <= d; i++)
for (int j = 0; j < m; j++) g[i * m + j] = a[i][j] == 1;
for (int i = 0; i < (d + 1) * m / 2; i++) swap(g[i], g[(d + 1) * m - i - 1]);
bit = log2(n * m + (d + 1) * m) + 1, lim = 1 << bit;
for (int i = 0; i < lim; i++)
rev[i] = rev[i >> 1] >> 1 | ((i & 1) << (bit - 1));
ntt(f, g);
for (int i = 0; i < n - d; i++)
for (int j = 0; j < m - r; j++) ans += !f[(d + i + 1) * m + j - 1];
cout << ans;
}

最新文章

  1. discuz首页设置默认地址不带forum.php后缀的方法
  2. Android 数据库框架OrmLite的使用(一)
  3. XHPROF相关内容
  4. 【Linux命令与工具】系统资源查看——free、uname、dmesg以及netstat
  5. javaweb实现验证码功能
  6. $(window)和$(document)
  7. DropDownList控件学习
  8. 在大型项目上,Python 是个烂语言吗
  9. WNDCLASS 窗口类结构
  10. centos6.9(Linux系统)安装VMware tools教程
  11. java基础复习+大数运算
  12. 连接器与容器的桥梁——CoyoteAdapter
  13. VC GDI 像素转厘米(英寸)[转发]
  14. JavaScript在网页中使用以及注意事项
  15. [HAOI 2015]按位或
  16. Alpha预乘-混合与不混合[转]
  17. 微信支付 统一下单 字段 body 为中文时 报【签名错误】解决方案(C# SDK)
  18. 《Toward an SDN-Enabled Big Data Platform for Social TV Analysis》--2015--Han Hu
  19. 【bzoj3091】 城市旅行
  20. 【Spring学习笔记-MVC-14】Spring MVC对静态资源的访问

热门文章

  1. 优雅解决 SpringBoot 工程中多环境下 application.properties 的维护问题
  2. js3——表格下拉
  3. 最小生成树——Kruskal与Prim算法
  4. 区块链学习笔记:D04 区块链在各行业领域的应用(二)
  5. luogu P1650 田忌赛马 |贪心
  6. luogu P4302 [SCOI2003]字符串折叠
  7. git 使用详解(6)—— 3种撤消操作
  8. ajax之三级联动(省市县)
  9. CodeForces1006C-Three Parts of the Array
  10. Selnium IDE插件的安装与简单使用