jzoj 5062.【GDOI2017第二轮模拟day1】航海舰队 fft

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/89351184

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

Input
第一行包含两个正整数n;m,分别表示地图的长和宽。
接下来n 行,每行有m 个字符,每个字符只能是“.”、“#”、“o” 中的一个。
输入数据保证至少有一个“o”。

Output
输出一行一个整数,即可以被经过的格子数的最大值。

Sample Input
4 5
…#
.o#.o
.o…o
…o…

Sample Output
12

Data Constraint
在这里插入图片描述

分析:
我们先找到一个最小的矩阵可以包含所有船。然后相当于在原图中对这个进行匹配。
可以考虑使用fft进行匹配,把原图中#设为1,船的矩阵中船设为1,然后匹配。可以得出每个节点成为矩阵左上角是否合法。
因为有的点合法但是到不了,所以我们要从初始点进行bfs求出可以到达的合法点。
一个节点可以到达满足左上角合法这个位置有船。可以用所有可以到达的合法点与船继续fft,大于0的点都可以到达。

代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>

const int N=2e6+7;
const int maxn=707;
const double pi=acos(-1);
const int dx[4]={0,1,0,-1};
const int dy[4]={1,0,-1,0};

using namespace std;

int n,m,len,ans;
int f[N],g[N],r[N];
bool vis[maxn][maxn];
char a[maxn][maxn];

struct node{
	int x,y;
};

queue <node> h;

struct rec{
	double x,y;
}x[N],y[N],z[N],w[N];

rec operator +(rec a,rec b)
{
    return (rec){a.x+b.x,a.y+b.y};
}

rec operator -(rec a,rec b)
{
    return (rec){a.x-b.x,a.y-b.y};
}

rec operator *(rec a,rec b)
{
    return (rec){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}

void fft(rec *a,int f)
{
    for (int i=0;i<len;i++)
    {
        if (i<r[i]) swap(a[i],a[r[i]]);
    }
    w[0]=(rec){1,0};
    for (int i=2;i<=len;i*=2)
    {
        rec wn=(rec){cos(2*pi/i),f*sin(2*pi/i)};
        for (int j=i/2;j>=0;j-=2) w[j]=w[j/2];
        for (int j=1;j<i/2;j+=2) w[j]=w[j-1]*wn;
        for (int j=0;j<len;j+=i)
        {
            for (int k=0;k<i/2;k++)
            {
                rec u=a[j+k],v=a[j+k+i/2]*w[k];
                a[j+k]=u+v;
                a[j+k+i/2]=u-v;
            }
        }
    }
}

void FFT(int *a,int *b,int *c,int n,int m)
{
    len=1;
    int k=0;
    while (len<(n+m)) len*=2,k++;
    for (int i=0;i<len;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(k-1));
    for (int i=0;i<len;i++)
    {
        int A,B;
        if (i<n) A=a[i]; else A=0;
        if (i<m) B=b[i]; else B=0;
        x[i]=(rec){A,0};
        y[i]=(rec){B,0};
    }
    fft(x,1),fft(y,1);
    for (int i=0;i<len;i++) z[i]=x[i]*y[i];
    fft(z,-1);
    for (int i=0;i<len;i++) c[i]=trunc(z[i].x/len+0.5);
}

int get(int x,int y)
{
	return (x-1)*m+y-1;
}

int main()
{
	freopen("sailing.in","r",stdin);
	freopen("sailing.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%s",a[i]+1);	
	int lc,rc,ls,rs,p,q;
	lc=ls=m;
	rc=rs=0;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			if (a[i][j]=='o')
			{
				lc=min(lc,i);
				ls=min(ls,j);
				rc=max(rc,i);
				rs=max(rs,j);
			}
		}
	}	
	p=rc-lc+1,q=rs-ls+1;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			f[get(i,j)]=(a[i][j]=='#');
			if (a[i][j]=='o') g[get(i-lc+1,j-ls+1)]=1;
		}
	}
	reverse(f,f+n*m);	
	FFT(f,g,f,n*m,n*m);
	reverse(f,f+n*m);	
	vis[lc][ls]=1;
	h.push((node){lc,ls});
	while (!h.empty())
	{
		node d=h.front();
		h.pop();
		int x=d.x,y=d.y;
		for (int i=0;i<4;i++)
		{
			if ((x+dx[i]>0) && (y+dy[i]>0) && (x+dx[i]<=n-p+1) && (y+dy[i]<=m-q+1))
			{
				if ((!f[get(x+dx[i],y+dy[i])]) && (!vis[x+dx[i]][y+dy[i]]))
				{
					vis[x+dx[i]][y+dy[i]]=1;
					h.push((node){x+dx[i],y+dy[i]});
				}
			}
		}
	}
	memset(f,0,sizeof(f));
	for (int i=1;i<=n-p+1;i++)
	{
		for (int j=1;j<=m-q+1;j++)
		{
			f[get(i,j)]=vis[i][j];
		}
	}
	FFT(f,g,f,n*m,n*m);
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)
		{
			if (f[get(i,j)]) ans++;
		}
	}
	printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/89351184
FFT