Description

​ 给你一个\(~n \times m~\)的\(~01~\)矩阵,一个人在这个矩阵中走了\(~k~\)步,每一次都往四联通方向中的一个走一步。给定这个人每一步走的方向,已知这个人经过的每一步都没有经过原矩阵中\(~1~\)的位置。问合法的起点有多少种?保证至少有一组解。\(~1 \leq n, m \leq 1500, ~k \leq 5 \times 10 ^ 6~\).

Solution

​ 不难发现那条路径通过补全\(~0~\)之后其实就是一个\(~01~\)矩阵,其中的\(~1~\)就是原路径。问题变成了把该矩阵放在原矩阵中(严格内含)不产生冲突的方案数,实质上就是起来全是\(~0~\)的方案数。考虑怎么快速求这个问题。把该矩阵通过补\(~0~\)变成和原矩阵一样大的规模,把两个矩阵都拉成长度为\(~n \times m~\)的序列,倒序一个序列做\(~FFT~\)或\(~NTT~\)在看对应位置上是否为\(~0~\)统计答案即可。至于这样为什么是对的,可以考虑这个对应位置的数代表的东西到底是什么,卷积中\(~ans_i~\)代表下标和为\(~i~\)的各项乘积之和,由于之前做过一个区间反转,所以这个\(~ans_i~\)就代表路径矩阵在原矩阵中起始位置为\(~i~\)时矩阵各项匹配起来的乘积的和,而在只有\(~0, 1~\)的情况下,乘法和或的运算法则一样。所以当\(~ans_i~\)为\(~0~\)时,就代表这个匹配位置是合法的,因为没有任何一个\(~1~\)同位。

Code

#include<bits/stdc++.h>
#define For(i, j, k) for(int i = j; i <= k; ++i)
#define Forr(i, j, k) for(int i = j; i >= k; --i)
using namespace std; inline int read() {
int x = 0, p = 1; char c = getchar();
for(; !isdigit(c); c = getchar()) if(c == '-') p = -1;
for(; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x *= p;
} inline void File() {
#ifndef ONLINE_JUDGE
freopen("loj6388.in", "r", stdin);
freopen("loj6388.out", "w", stdout);
#endif
} const int N = 1500 + 10, M = (N * N) << 2, mod = 998244353;
int a[M], b[M], rev[M], powg[M], invg[M], k;
int n, m, cnt1, cnt2, siz, len, bit, c[N << 1][N << 1];
char ss[M]; inline int qpow(int a, int b) {
static int res;
for (res = 1; b; a = 1ll * a * a % mod, b >>= 1)
if (b & 1) res = 1ll * res * a % mod;
return res;
} inline void NTT(int *a, int flag) {
For(i, 0, siz - 1) if (rev[i] > i) swap(a[rev[i]], a[i]);
for (int i = 2; i <= siz; i <<= 1) {
int wn = flag ? powg[i] : invg[i];
for (int j = 0; j < siz; j += i) {
int w = 1;
for (int k = 0; k < (i >> 1); ++ k, w = 1ll * w * wn % mod) {
int x = a[j + k], y = 1ll * w * a[j + k + (i >> 1)] % mod;
a[j + k] = (x + y) % mod, a[j + k + (i >> 1)] = (x - y + mod) % mod;
}
}
}
if (!flag) {
int g = qpow(siz, mod - 2);
For(i, 0, siz) a[i] = 1ll * a[i] * g % mod;
}
} int main() {
File();
n = read(), m = read(), k = read(); For(i, 1, n) {
scanf("%s", ss + 1);
For(j, 1, m) a[(i - 1) * m + j - 1] = ss[j] - 48;
}
cnt1 = n * m - 1; int x2 = n, y2 = m, x0 = n, y0 = m, lx = n, ly = m;
scanf("%s", ss + 1), c[lx][ly] = 1;
For(i, 1, k) {
if (ss[i] == 'w') c[-- lx][ly] = 1;
if (ss[i] == 'a') c[lx][-- ly] = 1;
if (ss[i] == 's') c[++ lx][ly] = 1;
if (ss[i] == 'd') c[lx][++ ly] = 1;
x0 = min(x0, lx), y0 = min(y0, ly);
x2 = max(x2, lx), y2 = max(y2, ly);
} For(i, x0, x0 + n - 1) For(j, y0, y0 + m - 1) b[cnt1 - (cnt2 ++)] = c[i][j];
-- cnt2; len = cnt1 + cnt2;
for (siz = 1; siz <= len; siz <<= 1) ++ bit;
For(i, 0, siz - 1) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1)); int g = qpow(3, mod - 2);
for (int i = 1; i <= siz; i <<= 1) {
invg[i] = qpow(g, (mod - 1) / i);
powg[i] = qpow(3, (mod - 1) / i);
} NTT(a, 1), NTT(b, 1);
For(i, 0, siz - 1) a[i] = 1ll * a[i] * b[i] % mod;
NTT(a, 0); int ans = 0;
For(i, 1, n - (x2 - x0)) For(j, 1, m - (y2 - y0))
if (a[cnt1 + (i - 1) * m + j - 1] == 0) ++ ans; cout << ans << endl;
return 0;
}

[loj6388] 「THUPC2018」赛艇 / Citing的更多相关文章

  1. 「THUPC2018」赛艇 / Citing

    https://loj.ac/problem/6388 矩形匹配,小地图经过位置为1,和大地图匹配不能同时存在一个1的位置,就可以是一个当前位置 1.bitset压位,....O(n^2m^2/64) ...

  2. 【LibreOJ】#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop 线段树+完全背包

    [题目]#6396. 「THUPC2018」弗雷兹的玩具商店 / Toyshop [题意]给定一个长度为n的物品序列,每个物品有价值.不超过m的重量.要求支持以下三种操作:1.物品价值区间加减,2.物 ...

  3. 【LibreOJ】#6392. 「THUPC2018」密码学第三次小作业 / Rsa 扩展欧几里得算法

    [题目]#6392. 「THUPC2018」密码学第三次小作业 / Rsa [题意]T次询问,给定正整数c1,c2,e1,e2,N,求正整数m满足: \(c_1=m^{e_1} \ \ mod \ \ ...

  4. 【LibreOJ】#6395. 「THUPC2018」城市地铁规划 / City 背包DP+Prufer序

    [题目]#6395. 「THUPC2018」城市地铁规划 / City [题意]给定n个点要求构造一棵树,每个点的价值是一个关于点度的k次多项式,系数均为给定的\(a_0,...a_k\),求最大价值 ...

  5. LOJ#6387 「THUPC2018」绿绿与串串 / String (Manacher || hash+二分)

    题目描述 绿绿和 Yazid 是好朋友.他们在一起做串串游戏. 我们定义翻转的操作:把一个串以最后一个字符作对称轴进行翻转复制.形式化地描述就是,如果他翻转的串为 RRR,那么他会将前 ∣R∣−1个字 ...

  6. 【LOJ】#6391. 「THUPC2018」淘米神的树 / Tommy

    题解 一道非常神仙的计数题 如果只有一个点,就是非常简单的树型dp \(f_{u} = (siz_{u} - 1)! \prod_{v \in son_{u}} \frac{f_{v}}{siz_{v ...

  7. loj6392 「THUPC2018」密码学第三次小作业 / Rsa

    还是挺好做的,\((e_1,e_2)=1 \Rightarrow e_1s+e_2t=0\),\(m \equiv m^1 \equiv m^{e_1s+e_2t} \equiv c_1^s c_2^ ...

  8. loj6387 「THUPC2018」绿绿与串串 / String

    还是很好做的,大致就是manacher,每个位置为中心的最长回文串要是能抵到最右边就合法,要是能抵到最左边,那这个点的是否合法取决于以这个点为中心的最长回文串的右端点是否合法. #include &l ...

  9. 【LOJ6397】「THUPC2018」蛋糕 / Cake(搜索)

    点此看题面 大致题意: 把一个\(a\times b\times c\times d\)的\(4\)维图形划分成\(a\times b\times c\times d\)个小块,求有\(0\sim8\ ...

随机推荐

  1. 安装pandas时出现环境错误

    在安装pandas时出现Could not install packages due to an EnvironmentErrorConsider using the `--user` option ...

  2. scrapy之环境安装

    scrapy之环境安装 在之前我安装了scrapy,但是在pycharm中却无法使用. 具体情况是: 我的电脑上存在多个python,有python2,python3,anaconda,其中anaco ...

  3. Python_动态参数、名称空间、作用域、作用域链、加载顺序、函数的嵌套、global、nonlocal

    1.动态参数 当实参数量与形参数量相等时,参数传递正常. def func1(a, b, c): pass func1(1, 2, 3) 当实参数量与形参数量不相等时,则会报错. def func1( ...

  4. php之IP

    常用的获取客户端的IP地址的方法: 1) function getRemoteIp(){ if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){ $ip = $_SE ...

  5. LR 两种html与url录制

    一直在使用LR,对于Html_based script和Url-based script 两种录制方式之间,要如何选择,仍是一知半解.最近测试时遇到同样的业务功能,两种录制方式的脚本,单次执行时间差别 ...

  6. ORACLE 当字段中有数据如何修改字段类型

    创建视图的时候,因为表太多,里面一些字段类型不一样,PL/SQL报错,为‘表达式必须具有对应表达式相同的数据类型’,发现后,一个字段的类型为CLOB和VARCHAR2(4000)两种,将CLOB进行修 ...

  7. Linux 查询oracle错误日志&警告日志

    1 通过命令查看错误日志目录:show parameter background_dump_dest /usr/oracle/app/diag/rdbms/orcl/orcl/trace   2 根据 ...

  8. 4.请介绍一下c++和Java的区别

    1.指针 2.c++多重继承,Java只能继承一个父类,但是可以继承多个接口 3.数据类型及类,Java完全面向对象,所有函数和变量都必须是类的一部分.而c++允许将函数和变量定义为全局,Java取消 ...

  9. InputFormat的数据划分、Split调度、数据读取

    在执行一个Job的时候,Hadoop会将输入数据划分成N个Split,然后启动相应的N个Map程序来分别处理它们.数据如何划分?Split如何调度(如何决定处理Split的Map程序应该运行在哪台Ta ...

  10. Hbase存储流程