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/ 站 ...
随机推荐
- 【第7篇】AI语音交互原理介绍
本章主要介绍AI语音交互的原理,包括语音交互的流程以及各流程节点所涉及的相关知识,如语音采集.语音识别.自然语言处理.语音合成等. 2.1 AI语音交互 AI语音交互通俗点说就是人与机器间进行语音理解 ...
- 关于CSDN微信登录接口的研究
代码 import requests import re from threading import Thread import time import requests from io import ...
- SDK怎么测试?俺不会啊
转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/7bc8d1c8.html 你好,我是测试蔡坨坨. 众所周知,在云产品和SaaS蓬勃发展的当下,企业中有许多系统和环节都是依赖 ...
- 2.2:常用的Python数据类型、字符串、dtype
一.内置数据类型 1.整型 2.浮点型 3.字符串 4.复数 5.布尔类型bool 6.None类型 二.字符串 1.从键盘输入数据 s = input() 2.用eval去引号求值 eval(&qu ...
- vulnhub靶场之DIGITALWORLD.LOCAL: FALL
准备: 攻击机:虚拟机kali.本机win10. 靶机:digitalworld.local: FALL,下载地址:https://download.vulnhub.com/digitalworld/ ...
- 10分钟看懂Docker和K8S,docker k8s 区别
10分钟看懂Docker和K8S,docker k8s 区别 2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫"dotCloud"的公司. 这家公司主要提供基于PaaS的 ...
- JavaScript入门⑧-事件总结大全
JavaScript入门系列目录 JavaScript入门①-基础知识筑基 JavaScript入门②-函数(1)基础{浅出} JavaScript入门③-函数(2)原理{深入}执行上下文 JavaS ...
- JavaScript冒泡排序+Vue可视化冒泡动画
冒泡排序(Bubble Sort)算是前端最简单的算法,也是最经典的排序算法了.网上JavaScript版本的冒泡排序很多,今天用Vue实现一个动态的可视化冒泡排序. 01.JavaScript冒泡排 ...
- 分布式注册服务中心etcd在云原生引擎中的实践
作者:王雷 etcd是什么 etcd是云原生架构中重要的基础组件,由CNCF孵化托管.ETCD是用于共享配置和服务发现的分布式,一致性的KV存储系统,是CoreOS公司发起的一个开源项目,授权协议为A ...
- 2022年7月12,第四组,周鹏,被算法折磨的一天【哭】【哭】【哭】【puls哭】
今天学习了JS的几种循环语法,说实话,前几天的简单让我大意了,没有闪,很成功的被搞崩了! 一杯水,一根烟,一个算法边写边骂是一天. 多少次,我满怀期待的以为它会出现想要的结果, 但现实的残酷狠狠的折磨 ...