bzoj5217 [Lydsy2017省队十连测] 航海舰队 FFT+bfs

版权声明:转吧转吧这条东西只是来搞笑的。。 https://blog.csdn.net/jpwang8/article/details/89318563

Description


有一个矩阵,有的位置有障碍
现在有一些关键点,每次这些关键点可以朝同一个方向同时走一步,要求任意关键点不能走到障碍上。问多少个点是可达的
n , m 700 n,m\le700

Solution


30分非常好写,只需要暴力bfs就可以了,字面意义上的暴力
60分就是记录左上角,然后二维前缀和一下bfs

先把包含关键点的最小矩阵抠出来,关键点移动就可以看成矩阵平移了。这个矩阵能够到达一个位置(x,y)的条件是,任意对应位置都不同时为1
考虑把这两个矩阵压成一维,那么就变成了字符匹配的问题,FFT就能搞。若结果第(x,y)位为0,说明以(x,y)为顶点的一个矩阵是可达的

搞出了所有可达的位置后,我们又可以发现一个位置能被走到,当且仅当存在一种对应情况使得两个串的某位都为1,于是这又是一个字符串匹配问题,再做一次FFT就行了

Code


#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <queue>

#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fi first
#define se second

typedef std:: pair <int,int> pair;
typedef long double ld;
const ld pi=acos(-1);
const int N=705;

struct com {
	ld r,i;
} a[N*N*3],b[N*N*3];

pair d[4];

com operator +(com a,com b) {return (com) {a.r+b.r,a.i+b.i};}
com operator -(com a,com b) {return (com) {a.r-b.r,a.i-b.i};}
com operator *(com a,com b) {return (com) {a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r};}
pair operator +(pair a,pair b) {return pair(a.fi+b.fi,a.se+b.se);}

char s[N][N];

int vis[N][N],rv[N*N*3],n,m;

void FFT(com *a,int n,int f) {
	for (int i=0;i<n;++i) if (i<rv[i]) std:: swap(a[i],a[rv[i]]);
	for (int i=1;i<n;i<<=1) {
		com wn=(com) {cos(pi/i),sin(pi/i)*f};
		for (int j=0;j<n;j+=(i<<1)) {
			com w=(com) {1,0};
			for (int k=0;k<i;++k,w=w*wn) {
				com u=a[j+k],v=a[j+k+i]*w;
				a[j+k]=u+v,a[j+k+i]=u-v;
			}
		}
	}
	if (f==-1) for (int i=0;i<n;++i) a[i].r/=n;
}

void bfs(pair st) {
	std:: queue <pair> que;
	que.push(st); vis[st.fi][st.se]=0;
	for (;!que.empty();) {
		pair now=que.front(); que.pop();
		a[(now.fi-1)*m+now.se]=(com) {1,0};
		rep(k,0,3) {
			pair tar=now+d[k];
			if (vis[tar.fi][tar.se]) {
				vis[tar.fi][tar.se]=0;
				que.push(tar);
			}
		}
	}
}

int main(void) {
	d[0]=pair(-1,0),d[1]=pair(1,0);
	d[2]=pair(0,-1),d[3]=pair(0,1);
	scanf("%d%d",&n,&m);
	int x1=n,y1=m,x2=0,y2=0;
	rep(i,1,n) {
		scanf("%s",s[i]+1);
		rep(j,1,m) {
			if (s[i][j]=='o') {
				x1=std:: min(x1,i);
				x2=std:: max(x2,i);
				y1=std:: min(y1,j);
				y2=std:: max(y2,j);
			} else if (s[i][j]=='#') {
				a[n*m-(i-1)*m-j]=(com) {1,0};
			}
		}
	}
	rep(i,1,n) rep(j,1,m) if (s[i][j]=='o') {
		b[(i-x1)*m+j-y1]=(com) {1,0};
	}
	int len=1,lg=0; for (;len<=n*m*2;) len<<=1,lg++;
	for (int i=0;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(lg-1));
	FFT(a,len,1),FFT(b,len,1);
	for (int i=0;i<len;++i) a[i]=a[i]*b[i];
	FFT(a,len,-1);
	rep(i,1,n-(x2-x1)) rep(j,1,m-(y2-y1)) {
		vis[i][j]=((int) (a[n*m-(i-1)*m-j].r+0.1)==0);
	}
	for (int i=0;i<len;++i) a[i]=(com) {0,0};
	bfs(pair(x1,y1));
	FFT(a,len,1);
	for (int i=0;i<len;++i) a[i]=a[i]*b[i];
	FFT(a,len,-1);
	int ans=0;
	for (int i=0;i<n*m;++i) ans+=((int) (a[i].r+0.1))>0;
	printf("%d\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/89318563