https://www.lydsy.com/JudgeOnline/problem.php?id=5217

Byteasar 组建了一支舰队!他们现在正在海洋上航行着。海洋可以抽象成一张n×m 的网格图,其中有些位置是“.”,表示这一格是海水,可以通过;有些位置是“#”,表示这一格是礁石,不可以通过;有些位置是“o”,表示这一格目前有一艘舰,且舰离开这一格之后,这一格将变为“.”。这些“o” 表示Byteasar 的舰队,他们每天可以往上下左右中的一个方向移动一格,但不能有任何一艘舰驶出地图。特别地,Byteasar 对阵形有所研究,所以他不希望在航行的过程中改变阵形,即任何时刻任何两艘舰的相对位置都不能发生变化。Byteasar 的舰队可以航行无限长的时间,每当一艘舰经过某个格子的时候,这个格子海底的矿藏都将被Byteasar 获得。请写一个程序,帮助Byteasar 计算他最多可以获得多少个格子海底的矿藏?

很妙……如果没有做过类似的题可能打死也不知道是道FFT题。

首先将最小的包含所有舰队的矩形拿出来,那么先不考虑能否到达,我们只需要将这个小矩形和大矩形匹配,就能知道我们舰队能够放在哪里。

于是想到暴力匹配,但是显然是过不了的。

想到BZOJ4259:残缺的字符串这道题,但是那是一维匹配,而我们要二维匹配。

所以一个想法就是降维,简单点说,就是第一行字符+第二行字符+……

设大矩形为a[],小矩形(需要将大小填充等于大矩形)为b[]。

对于一个合法的匹配位置的左上角下标为p,则有对于所有的位置,都不能存在a[p+i]有礁石,b[i]有舰队这种情况。

于是令a中礁石=1,b中舰队=1,则就是f[i]=sigma(a[i+j]*b[j])=0,将a矩阵倒存,就有f[i]=sigma(a[n*m-i-j]*b[j])是一个卷积形式,于是FFT。

接下来考虑,对于所有的左上角,我们并不是都能到达的,所以从小矩阵最开始的左上角搜索找到所有合法的左上角。

最后就是一个点其下标为p,它能到达当其存在一个左上角p-i合法,且b[i]=1,于是令所有合法左上角=1,则f[i]=sigma(a[i-j]*b[j])>0,直接就是一个卷积,FFT求一遍就行了。

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef double dl;
typedef pair<int,int>pii;
#define fi first
#define se second
const dl pi=acos(-1.0);
const dl eps=0.5;
const int M=;
const int N=M*M*;
struct complex{
dl x,y;
complex(dl xx=,dl yy=){
x=xx;y=yy;
}
complex operator +(const complex &b)const{
return complex(x+b.x,y+b.y);
}
complex operator -(const complex &b)const{
return complex(x-b.x,y-b.y);
}
complex operator *(const complex &b)const{
return complex(x*b.x-y*b.y,x*b.y+y*b.x);
}
};
void FFT(complex a[],int n,int on){
for(int i=,j=n>>;i<n-;i++){
if(i<j)swap(a[i],a[j]);
int k=n>>;
while(j>=k){j-=k;k>>=;}
if(j<k)j+=k;
}
for(int i=;i<=n;i<<=){
complex res(cos(-*on*pi/i),sin(-*on*pi/i));
for(int j=;j<n;j+=i){
complex w(,);
for(int k=j;k<j+i/;k++){
complex u=a[k],t=w*a[k+i/];
a[k]=u+t;a[k+i/]=u-t;
w=w*res;
}
}
}
if(on==-)
for(int i=;i<n;i++)a[i].x/=n;
}
bool vis[M][M];
int n,m;
int dx[]={,,,-};
int dy[]={,,-,};
char mp[M][M];
complex a[N],b[N];
queue<pii>q;
void bfs(int sx,int sy){
q.push(pii(sx,sy));
vis[sx][sy]=;
while(!q.empty()){
int x=q.front().fi,y=q.front().se;q.pop();
a[(x-)*m+y-]=complex(,);
for(int i=;i<;i++){
int nx=x+dx[i],ny=y+dy[i];
if(vis[nx][ny]){
vis[nx][ny]=;
q.push(pii(nx,ny));
}
}
}
}
int main(){
int x1=M,y1=M,x2=,y2=;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)scanf("%s",mp[i]+); for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(mp[i][j]=='o')x1=min(x1,i),y1=min(y1,j),x2=max(x2,i),y2=max(y2,j);
else if(mp[i][j]=='#')a[n*m-(i-)*m-j]=complex(,);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(mp[i][j]=='o')b[(i-x1)*m+j-y1]=complex(,); int len=;
while(len<n*m)len<<=;
FFT(a,len,);FFT(b,len,);
for(int i=;i<len;i++)a[i]=a[i]*b[i];
FFT(a,len,-);
for(int i=;i<=n-(x2-x1);i++)
for(int j=;j<=m-(y2-y1);j++)
if(a[n*m-(i-)*m-j].x<eps)vis[i][j]=;
for(int i=;i<len;i++)a[i]=complex(,);
bfs(x1,y1);
FFT(a,len,);
for(int i=;i<len;i++)a[i]=a[i]*b[i];
FFT(a,len,-);
int ans=;
for(int i=;i<n*m;i++)if(a[i].x>eps)ans++;
printf("%d\n",ans);
return ;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ5217:[Lydsy2017省队十连测]航海舰队——题解的更多相关文章

  1. BZOJ5217: [Lydsy2017省队十连测]航海舰队 FFT

    被FFT的空间卡了半天 后来发现根本不用开那么大... 首先可以把包含舰艇的那个小矩形找出来 将它一行一行连接成一个串T 其中舰艇位置为1其他位置为0 将大矩形也连成串S 其中礁石为1其他为0 两个串 ...

  2. bzoj 5217: [Lydsy2017省队十连测]航海舰队

    Description Byteasar 组建了一支舰队!他们现在正在海洋上航行着.海洋可以抽象成一张n×m 的网格图,其中有些位置是" .",表示这一格是海水,可以通过:有些位置 ...

  3. Lydsy2017省队十连测

    5215: [Lydsy2017省队十连测]商店购物 可能FFT学傻了,第一反应是前面300*300背包,后面FFT... 实际上前面背包,后面组合数即可.只是这是一道卡常题,需要注意常数.. //A ...

  4. bzoj 5216 [Lydsy2017省队十连测]公路建设 线段树维护 最小生成树

    [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 93  Solved: 53[Submit][Status][ ...

  5. bzoj 5216: [Lydsy2017省队十连测]公路建设

    5216: [Lydsy2017省队十连测]公路建设 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 66  Solved: 37[Submit][St ...

  6. 2018.09.26 bzoj5218: [Lydsy2017省队十连测]友好城市(回滚莫队)

    传送门 比较简单的一道回滚莫队吧. 每次询问用bitset优化kosaraju统计答案. 就是有点难调. 然后向dzyo学长学习了回滚莫队的一种简洁的实现方式,就是直接建立一个sqrt(m)∗sqrt ...

  7. bzoj 5218: [Lydsy2017省队十连测]友好城市

    题意: 这题显然直接tarjan是做不了的. 这里安利另一个求SCC的算法Kosaraju,学习的话可以见这篇博客 于是结合莫队,我们有了个暴力. 发现主要瓶颈是dfs过程中找最小的未经过的点,我们用 ...

  8. 【BZOJ 5222】[Lydsy2017省队十连测]怪题

    题目大意: 传送门 给一个长度为$n(n<=200)$的数列$h$,再给$m$个可以无限使用的操作,第$i$个操作为给长度为花费$c_i$的价值给长度为$l_i$的数列子序列+1或-1,求将数列 ...

  9. 2018.09.26 bzoj5221: [Lydsy2017省队十连测]偏题(数学推导+矩阵快速幂)

    传送门 由于没有考虑n<=1的情况T了很久啊. 这题很有意思啊. 考试的时候根本不会,骗了30分走人. 实际上变一个形就可以了. 推导过程有点繁杂. 直接粘题解上的请谅解. 不得不说这个推导很妙 ...

随机推荐

  1. 关于mongodb的mapReduce

    由于nodejs本身的限制,在程序中使用js进行大批量计算效率不高.而V8引擎自身对内存大小的限制(64位系统下1.4G),同样限制了数据规模. 因此,相对于从mongodb中抽出数据进行计算,在mo ...

  2. JMeter自学笔记3-创建自己的第一个测试用例

    一.写在前面的话: 上篇我们已经认识了JMeter的图形界面,大家应该都是很懵的.那么这篇,我们将学习使用JMeter创建第一个属于自己测试用例. 二.创建自己的第一个测试用例: 1.新建一个Thre ...

  3. TPO-12 C2 A problem of the TA's payroll

    TPO-12 C2 A problem of the TA's payroll payroll n. 工资单:在册职工人数:工资名单: paycheck n. 付薪水的支票,薪水 paperwork ...

  4. lesson 16 Mary had a little lamb

    lesson 16 Mary had a little lamb a little + 可数 小的;+ 不可数 少量的 对于动物在幼时都有不同的称呼: calf 小牛 lamb 羊羔 piglet 小 ...

  5. es6笔记4^_^function

    一.function默认参数 现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了. es5 function sayHello(name){ //传统的指定默认参 ...

  6. 博客更换至 www.zhaoch.top

    博客更换至 www.zhaoch.top 随手拷了一些链接 http://www.zhaoch.top/操作系统/linux/常用命令备忘.html http://www.zhaoch.top/操作系 ...

  7. 【view】 视图组件说明

    view 是视图容器,可用于包裹其它组件或文本内容. 原型: <view hover-class="[String]" hover-stop-propagation=&quo ...

  8. SVM 为什么要从原始问题变为对偶问题来求解

    这个问题困扰了我许久,下面是我搜集整理到的答案 对偶问题将原始问题中的约束转为了对偶问题中的等式约束 方便核函数的引入 改变了问题的复杂度.由求特征向量w转化为求比例系数a,在原始问题下,求解的复杂度 ...

  9. JS判断是IOS还是Android以及如何解决h5打包后在ios下内容与状态栏重叠问题

    h5打包后在ios下内容与状态栏重叠问题: 1:知道设备的类型: var u = navigator.userAgent, app = navigator.appVersion; var isAndr ...

  10. Java学习个人备忘录之构造函数&this

    构造函数 概念:构建创造对象时调用的函数. 作用:可以给对象进行初始化,创建对象都必须要通过构造函数初始化. 一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数.如果在类中定义了指 ...