JZOJ 5062. 【GDOI2017第二轮模拟day1】航海舰队
\(\text{Solution}\)
这还是 [Lydsy2017省队十连测] 的题
不得不说 \(FFT\) 在字符串匹配中的妙啊!
前面做了道一维的题,现在这是二维的
从题目入手,不考虑可不可达
如果舰队从天而降,考虑其可以落到以那些点为左上角的点
先将地图压成一维,一行接着一行,礁石处为 \(1\) 其余为 \(0\)
抽出包含舰队的最小矩形,按照原来地图行长,从矩阵开头到结尾压成一维,舰队处为 \(1\),其余为 \(0\)
构造匹配函数 \(F_i\) 表示大矩形以 \(i\) 为左上角能否匹配,\(F_i =\sum_j A_{i+j}\cdot B_j\)
则 \(F_i = 0\) 是可行,将 \(A\) 翻转,\(F_i=\sum_j A_{n\cdot m-1-i-j}\cdot B_j\)
这是一个多项式卷积形式,\(NTT\) 即可
于是我们得到了若干个可放入舰队的左上角
我们还要知道那些左上角可达,从小矩阵左上角开始 \(BFS\) 即可
然而我们仍需要那些空地可以被舰队掠过
考虑将可达左上角即为 \(1\),其余为 \(0\),\(B\) 中舰队为 \(1\)
那么 \(i\) 位置可达,需要存在一个可达左上角 \(i-j\)
考虑构造函数 \(F_i = \sum_j A_{i-j} \cdot B_{j}\)
当 \(F_i > 0\) 则该位置可达
发现仍是多项式卷积形式,继续 \(NTT\) 即可
\(\text{Code}\)
#include <cstdio>
#include <iostream>
#define RE register
#define IN inline
using namespace std;
typedef long long LL;
const int N = 705, P = 998244353, g = 3;
char str[N][N];
int n, m, vis[N][N], x0 = N, y0 = N, x1 = 0, y1 = 0, rev[N * N * 2];
int fx[4][2] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}};
LL a[N * N * 2], b[N * N * 2];
struct Point{int x, y;}Q[N * N];
IN int Get(int x, int y){return (x - 1) * m + y - 1;}
IN int get(int x, int y){return (x - x0) * m + y - y0;}
IN int fpow(LL x, int y){LL s = 1; for(; y; y >>= 1, x = x * x % P) if (y & 1) s = s * x % P; return s;}
IN void NTT(LL *a, int n, int inv)
{
if (n == 1) return;
for(RE int i = 0; i < n; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
for(RE int mid = 1; mid < n; mid <<= 1)
{
int I = fpow(g, (P - 1) / (mid << 1));
if (inv == -1) I = fpow(I, P - 2);
for(RE int i = 0; i < n; i += (mid << 1))
{
LL W = 1;
for(RE int j = 0, x, y; j < mid; j++, W = W * I % P)
x = a[i + j], y = W * a[i + j + mid] % P,
a[i + j] = (x + y) % P, a[i + j + mid] = (x - y + P) % P;
}
}
}
void BFS()
{
int head = 0, tail = 1; Q[1] = Point{x0, y0}, vis[x0][y0] = 0;
while (head < tail)
{
Point z = Q[++head]; a[Get(z.x, z.y)] = 1;
for(RE int k = 0; k < 4; k++)
{
int x = z.x + fx[k][0], y = z.y + fx[k][1];
if (x > 0 && x <= n && y > 0 && y <= m && vis[x][y]) vis[x][y] = 0, Q[++tail] = Point{x, y};
}
}
}
int main()
{
freopen("sailing.in", "r", stdin), freopen("sailing.out", "w", stdout);
scanf("%d%d", &n, &m);
for(RE int i = 1; i <= n; i++) scanf("%s", str[i] + 1);
for(RE int i = 1; i <= n; i++)
for(RE int j = 1; j <= m; j++)
if (str[i][j] == 'o') x0 = min(x0, i), y0 = min(y0, j), x1 = max(x1, i), y1 = max(y1, j);
else if (str[i][j] == '#') a[n * m - 1 - Get(i, j)] = 1;
for(RE int i = 1; i <= n; i++)
for(RE int j = 1; j <= m; j++) if (str[i][j] == 'o') b[get(i, j)] = 1;
int lim = 1; while (lim < n * m) lim <<= 1; int inv = fpow(lim, P - 2);
int bit = 0; while ((1 << bit) < lim) bit++;
for(RE int i = 0; i < lim; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
NTT(a, lim, 1), NTT(b, lim, 1);
for(RE int i = 0; i < lim; i++) a[i] = a[i] * b[i] % P;
NTT(a, lim, -1); for(RE int i = 0; i < lim; i++) a[i] = a[i] * inv % P;
for(RE int i = 1; i <= n + x0 - x1; i++)
for(RE int j = 1; j <= m + y0 - y1; j++)
if (!a[n * m - 1 - Get(i, j)]) vis[i][j] = 1;
for(RE int i = 0; i < lim; i++) a[i] = 0;
BFS(), NTT(a, lim, 1);
for(RE int i = 0; i < lim; i++) a[i] = a[i] * b[i] % P;
NTT(a, lim, -1); for(RE int i = 0; i < lim; i++) a[i] = a[i] * inv % P;
int ans = 0;
for(RE int i = 0; i < n * m; i++) if (a[i] > 0) ans++;
printf("%d\n", ans);
}
JZOJ 5062. 【GDOI2017第二轮模拟day1】航海舰队的更多相关文章
- GDOI2017第二轮模拟day1 总结
平民比赛 这场比赛的暴力分非常友好. 但是我并没有拿到全部的暴力分. 1(暴力分\(60/100\)) 暂时我可以拿的暴力分为\(30/100\),直接mst模拟即可. 然而当时打了个辣鸡莫队,结果爆 ...
- 【JZOJ5060】【GDOI2017第二轮模拟day1】公路建设 线段树+最小生成树
题面 在Byteland一共有n 个城市,编号依次为1 到n,它们之间计划修建m条双向道路,其中修建第i 条道路的费用为ci. Byteasar作为Byteland 公路建设项目的总工程师,他决定选定 ...
- [jzoj5073 GDOI2017第二轮模拟] 影魔
Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵 ...
- 【JZOJ5064】【GDOI2017第二轮模拟day2】友好城市 Kosarajo算法+bitset+ST表+分块
题面 在Byteland 一共有n 座城市,编号依次为1 到n,这些城市之间通过m 条单向公路连接. 对于两座不同的城市a 和b,如果a 能通过这些单向道路直接或间接到达b,且b 也能如此到达a,那么 ...
- 【JZOJ5086】【GDOI2017第四轮模拟day1】数列 折半搜索
题面 有一个长度为n 的排列,现在有一些位置的数已经模糊不清了,你只知道这个排列的逆序对个数是K,你能计算出总共有多少可能的排列吗? 对于100% 的数据,n <=10^3,K<=10^9 ...
- 【JZOJ5071】【GDSOI2017第二轮模拟】奶酪 树形dp
题面 CJY很喜欢吃奶酪,于是YJC弄到了一些奶酪,现在YJC决定和CJY分享奶酪. YJC弄到了n-1块奶酪,于是他把奶酪挂在了一棵n个结点的树上,每根树枝上挂一块奶酪,每块奶酪都有重量. YJC和 ...
- 【JZOJ5068】【GDSOI2017第二轮模拟】树 动态规划+prufer序列
题面 有n个点,它们从1到n进行标号,第i个点的限制为度数不能超过A[i]. 现在对于每个s (1 <= s <= n),问从这n个点中选出一些点组成大小为s的有标号无根树的方案数. 10 ...
- DFRobot万物互联大赛第二轮
前言 最近放在阳台的花草被啥东西给吃了,然后厨房挂在墙上的小虾米也不知道咋的被抓破吃光了(我怀疑是隔隔壁两条泰迪),所以打算做个简单的项目,教训一下偷吃贼.时间比较仓促,内容比较多,能力有比较有限,好 ...
- LOJ 6060「2017 山东一轮集训 Day1 / SDWC2018 Day1」Set(线性基,贪心)
LOJ 6060「2017 山东一轮集训 Day1 / SDWC2018 Day1」Set $ solution: $ 这一题的重点在于优先级问题,我们应该先保证总和最大,然后再保证某一个最小.于是我 ...
- 【百度之星2014~初赛(第二轮)解题报告】Chess
声明 笔者近期意外的发现 笔者的个人站点http://tiankonguse.com/ 的非常多文章被其他站点转载.可是转载时未声明文章来源或參考自 http://tiankonguse.com/ 站 ...
随机推荐
- 解决can't compare offset-naive and offset-aware datetimes报错
问题描述 在比较 <class 'datetime.datetime'> 类型时,抛出异常 原因 俩个做比较的,一个具有时区,一个不具有时区 解决 如果可以确认俩个时间都是本地时间可以将时 ...
- 关于 Windows6.1-KB2999226-x64.msu 此更新不适用你的计算机解决办法
前言 今天被这个破问题坑了很长时间,网上一大堆扯跳过那个检查,通过提取 cab 文件然后直接用命令安装,我可以明确的告诉你不是那样的解决的,因为我实际用命令装过也装不上(这里我吐槽一下,我猜你最初的问 ...
- 同一服务器部署多tomcat以及MyEclipse添加多tomcat
tomcat有很多版本但他们的部署方式并不因为版本的不同而改变其的部署方式,操作者不必考虑此等原因.本人办公电脑使用的是tomcat7,家里自用的是6版本,这里就以6版本为例实现同一台机器上部署多to ...
- HBX更新后无法打包
HBX更新到3.2.2.20210818后H5打包增加了校验 HBuilder X - Release Notes ====================================== 3.2 ...
- form表单里的button 等元素不能使用margin: 0 auto;
记得把form和button都设为display:block; 就能用margin: 0 auto;水平居中了
- java逻辑运算&&与&的区别
本文主要阐述&&(短路与)和&(逻辑与)的运算异同:a && b 和 a&b : 共同之处是只有a和b同时为真时,结果才为真,否则为假 不同点在于 a ...
- 丧心病狂,竟有Thread.sleep(0)这种神仙写法?
前言 最近在网上看到了一段代码,让我感到很迷茫.他在代码中使用了 Thread.sleep(0),让线程休眠时间为0秒,具体代码如下. int i = 0; while (i<10000000) ...
- 基于Chromium开发的称重软件,集称重、计价、打印于一体,支持耀华、顶尖等多个厂家设备型号
技术方案: 1.运行时使用.Net Framework4.6框架,界面使用WPF与Chromium. 2.上位机与下位机使用串口对接每家设备协议,上位机与UI使用WebSocket通讯. 3.数据库使 ...
- Java正则表达式全局匹配
今天想用Java的正则在字符串中匹配特定内容,但是当我代码写好运行后却发现正则表达式并没有起作用 试了很多方法,也去Js里试了正则表达式可以走通,就是Java不行 很纳闷 (:′⌒`) Java里正则 ...
- 【深入浅出Seata原理及实战】「入门基础专题」带你透析认识Seata分布式事务服务的原理和流程(1)
分布式事务的背景 随着业务的不断发展,单体架构已经无法满足我们的需求,分布式微服务架构逐渐成为大型互联网平台的首选,但所有使用分布式微服务架构的应用都必须面临一个十分棘手的问题,那就是"分布 ...