bzoj 5217: [Lydsy2017省队十连测]航海舰队
Description
Byteasar 组建了一支舰队!他们现在正在海洋上航行着。海洋可以抽象成一张n×m 的网格图,其中有些位置是“
.”,表示这一格是海水,可以通过;有些位置是“#”,表示这一格是礁石,不可以通过;有些位置是“o”,表
示这一格目前有一艘舰,且舰离开这一格之后,这一格将变为“.”。这些“o” 表示Byteasar 的舰队,他们每天
可以往上下左右中的一个方向移动一格,但不能有任何一艘舰驶出地图。特别地,Byteasar 对阵形有所研究,所
以他不希望在航行的过程中改变阵形,即任何时刻任何两艘舰的相对位置都不能发生变化。Byteasar 的舰队可以
航行无限长的时间,每当一艘舰经过某个格子的时候,这个格子海底的矿藏都将被Byteasar 获得。请写一个程序
,帮助Byteasar 计算他最多可以获得多少个格子海底的矿藏?
Solution
要解决两个问题
首先要求出原矩阵中的哪些子矩阵可以放下这个舰队所在的小矩阵
那么如果把障碍看作 \(1\),舰队所在的位置看作 \(1\),如果对应位置相乘不为都 \(1\),那么就是可以放的
我们把矩阵变成一个序列(把第二行接在第一行的后面,以此类推),实际上就是两个序列对应位置相乘不等于 \(1\)
把第二个序列反过来,就是一个卷积形式了,\(FFT\) 一遍就可以知道哪些位置是可以放舰队的了
能够放,但是不一定可以从初始矩阵走到,我们 \(bfs\) 一遍,把可以放且能走到的位置标为 \(1\),那么就是可以放舰队的位置了
舰队是一个矩阵,而且内部有障碍物,且直接计算答案会算重,复杂度也不对
一个格子的矿藏能获得当且仅当这个格子可以走到并且这个格子和某个时刻的舰队处于同一矩阵中
我们再把可以放且能走到的位置标为 \(1\),并且看作一个序列,并且和舰队对应的矩阵相乘,\(FFT\) 一下
结果中 \(1\) 的个数就是答案
复杂度 \(O(n*m*log)\)
#include<bits/stdc++.h>
using namespace std;
typedef complex<double> dob;
const int M=710,N=2e6+10;const double pi=acos(-1.0);
char s[M][M];int n,m,T[N],R[N],L=0,E;
inline void FFT(dob *A,int o){
for(int i=0;i<E;i++)if(i<R[i])swap(A[i],A[R[i]]);
for(int i=1;i<E;i<<=1){
dob wn(cos(pi/i),sin(o*pi/i)),x,y;
for(int j=0;j<E;j+=(i<<1)){
dob w(1,0);
for(int k=0;k<i;k++,w*=wn){
x=A[j+k];y=w*A[j+k+i];
A[j+k]=x+y;A[j+k+i]=x-y;
}
}
}
}
dob A[N],B[N];bool vis[M][M],d[N];
struct data{int x,y;};
int mx[4]={1,-1,0,0},my[4]={0,0,1,-1};
inline void bfs(data S){
memset(A,0,sizeof(A));
queue<data>Q;
Q.push(S);
while(!Q.empty()){
data t=Q.front();Q.pop();
for(int i=0;i<4;i++){
data u=(data){t.x+mx[i],t.y+my[i]};
if(t.x<0 || t.y<0)continue;
int v=u.x*m+u.y;
if(!vis[u.x][u.y] || d[v])continue;
d[v]=1;A[v]=1;Q.push(u);
}
}
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
cin>>n>>m;
int xl=N,xr=0,yl=N,yr=0;
for(int i=0;i<n;i++)scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='#')B[i*m+j]=1;
else if(s[i][j]=='o'){
xl=min(xl,i);xr=max(xr,i);
yl=min(yl,j);yr=max(yr,j);
}
for(int i=xl;i<=xr;i++)
for(int j=yl;j<=yr;j++)
if(s[i][j]=='o')T[(i-xl)*m+j-yl]=1;
int r=(xr-xl+1),c=(yr-yl+1),len=(r-1)*m+c;
for(E=1;E<=n*m;E<<=1)L++;
for(int i=0;i<E;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
for(int i=0;i<len;i++)A[len-1-i]=T[i];
FFT(A,1);FFT(B,1);
for(int i=0;i<=E;i++)A[i]*=B[i];
FFT(A,-1);
for(int i=r-1;i<n;i++)
for(int j=c-1;j<m;j++)
if(!(int)(A[i*m+j].real()/E+0.5))vis[i][j]=1;
bfs((data){xr,yr});
for(int i=0;i<E;i++)B[i]=T[i];
FFT(A,1);FFT(B,1);
for(int i=0;i<=E;i++)A[i]*=B[i];
FFT(A,-1);
int ans=0;
for(int i=0;i<E;i++)if((int)(A[i].real()/E+0.5))ans++;
printf("%d\n",ans);
return 0;
}
bzoj 5217: [Lydsy2017省队十连测]航海舰队的更多相关文章
- BZOJ5217:[Lydsy2017省队十连测]航海舰队——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=5217 Byteasar 组建了一支舰队!他们现在正在海洋上航行着.海洋可以抽象成一张n×m 的网格 ...
- BZOJ5217: [Lydsy2017省队十连测]航海舰队 FFT
被FFT的空间卡了半天 后来发现根本不用开那么大... 首先可以把包含舰艇的那个小矩形找出来 将它一行一行连接成一个串T 其中舰艇位置为1其他位置为0 将大矩形也连成串S 其中礁石为1其他为0 两个串 ...
- bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树
[Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 93 Solved: 53[Submit][Status][ ...
- bzoj 5216: [Lydsy2017省队十连测]公路建设
5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 66 Solved: 37[Submit][St ...
- bzoj 5218: [Lydsy2017省队十连测]友好城市
题意: 这题显然直接tarjan是做不了的. 这里安利另一个求SCC的算法Kosaraju,学习的话可以见这篇博客 于是结合莫队,我们有了个暴力. 发现主要瓶颈是dfs过程中找最小的未经过的点,我们用 ...
- BZOJ 5215: [Lydsy2017省队十连测]商店购物
裸题 注意+特判 #include<cstdio> using namespace std; const int mod=1e9+7; int F[1000005],mi[10000005 ...
- @bzoj - 5219@ [Lydsy2017省队十连测]最长路径
目录 @description@ @solution@ @accepted code@ @details@ @description@ 在Byteland一共有n个城市,编号依次为1到n,形成一个n个 ...
- Lydsy2017省队十连测
5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...
- 【BZOJ 5222】[Lydsy2017省队十连测]怪题
题目大意: 传送门 给一个长度为$n(n<=200)$的数列$h$,再给$m$个可以无限使用的操作,第$i$个操作为给长度为花费$c_i$的价值给长度为$l_i$的数列子序列+1或-1,求将数列 ...
随机推荐
- golang subprocess tests
golang Subprocess tests Sometimes you need to test the behavior of a process, not just a function. f ...
- MongoVue 破解治标不治本
MongoVue 破解治标不治本 ---------解决燃眉之急 注册表中查找B1159E65-821C3-21C5-CE21-34A484D54444中的子项4FF78130 ,删除其下的三个子项 ...
- sqlServer组合主键
sqlServer 组合主键 创建表时: create table Person ( Name1 ) not null ,Name2 ) not null primary key(Name1,Na ...
- WebStorm安装与快捷键
WebStorm是JetBrains 推出的一款强大的HTML5编辑工具(特别开发JavaScript非常好用),被JavaScript开发者誉为“web前端开发神奇”.“最强悍的JavaScript ...
- 【Guava】RateLimiter类
Guava官方文档-RateLimiter类 原文链接 作者:Dimitris Andreou 译者:魏嘉鹏 校对:方腾飞 RateLimiter 从概念上来讲,速率限制器会在可配置的速率下分配许可 ...
- 最小生成树问题:Kruskal算法 AND Prim算法
Kruskal算法: void Kruskal ( ) { MST = { } ; //边的集合,最初为空集 while( Edge ...
- fork()父子进程文件描述符的关系
父子进程共享文件描述符:此说法,其实是父子进程共享 文件表项(父进程和子进程共享同一个file table entry) 由于子进程是父进程的拷贝,子进程会拷贝父进程的进程描述符中的文件描述符表,可以 ...
- RPC 定义 和 原理
一.RPC 1. RPC是什么 RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议. ...
- PHP sprintf() 函数
PHP sprintf() 函数 先说下为什么要写这个函数的前言,这个是我在微信二次开发的一个token验证文档也就是示例文档看到的一个函数,当时非常不理解,于是查了百度,但是很多结果都很笼统,结果也 ...
- [转] Kubernetes K8S 简介
[From] https://blog.csdn.net/zhangxxxww/article/details/73547251 Kubernetes(k8s)是自动化容器操作的开源平台,这些操作包括 ...