zoukankan      html  css  js  c++  java
  • BZOJ 5217 [Lydsy2017省队十连测] 航海舰队

    题意

    真的想不到是(FFT)的题,用了一个晚上基本弄懂了。

    首先我们要解决的是用一个小矩形在一个大矩形上匹配的问题,如果是一维的就是这道题

    现在是二维的,我们将每一行拆出来,按照第(1)行、第(2)行、...、第(n)行的顺序拼接在一起,拼出一个长为(n*m)的串,考虑在这上面解决问题。

    我们先找到最小的包含舰队的矩形,将这个矩阵作为左上角的补成一个(n*m)的矩形,我们称为舰队矩形,我们将这个矩形也按照刚才的方式处理成一个串。

    拿样例举个例子:
    图:

    ....#
    .o#.o
    .o..o
    ..o..
    

    最小的包含舰队的矩形:

    o#.o
    o..o
    .o..
    

    舰船矩形:

    o#.o.
    o..o.
    .o...
    .....
    

    现在我们有两个串,一个是图的串,我们称为(s),另一个是舰队矩形的串,我们称为(t)

    我们对这个两个串构建两个序列(a,b)
    (a)这个序列是对(s)构建的,其中:(a_i=[s_i=#]),即如果(i)这个点是障碍,那么(a_i=1)
    (b)这个序列是对(t)构建的,其中(b_i=[t_i=o]),即如果(i)这个点在舰队矩形中为船,那么(b_i=1)。它实际上表示的是各个舰船和最靠左上的舰船的相对位置,这样对于(s)中任意位置(x),用(b_{i})即可表示以(x)为左上角时(s_{x+i})处是否有舰船。

    我们现在考虑一个位置(x),我们要判断(x)是否能成为舰队矩形的左上角,即是否能将舰队移到这个位置。
    如果(x)满足条件,当且仅当((sumlimits_{i=0}^{nm-x-1}a_{x+i}b_i)=0),这表示不存在一个(i)满足(a_{x+i}=1&&b_i=1),即每个船应该在的位置都没有障碍。

    我们将(a)翻转过来变为(a'),那么上面的式子就变为:((sumlimits_{i+j=nm-x}a'_ib_j)=0),它其实就是(sumlimits_{i+j=x}a'_ib_j)翻转一下,我们可以(FFT)快速求出。

    现在我们求出了所有可以放上的点,但是有些点可能无法到达,我们再跑个(bfs)将这些无法到达的点排除就好了。

    之后我们要求出有多少点能被舰队覆盖,现在我们知道了所有能到达的左上角,它对应的序列为(a)(如果(i)这个点能到且是合法的左上角,那么(a_i=1)),那么一个位置(x)能被覆盖当且仅当:((sumlimits_{i+j=x}a_ib_j)>0)即至少存在一个左端点(i),且(i+j)这个位置有舰船,这个卷积就更裸了。

    code:

    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<queue>
    using namespace std;
    #define pii pair<int,int>
    #define mkp make_pair
    #define fir first
    #define sec second
    const int maxn=710;
    const int maxm=2000010;
    const int inf=1e9;
    const int dx[]={-1,1,0,0};
    const int dy[]={0,0,-1,1};
    const double Pi=acos(-1.0);
    const double eps=0.5;
    int n,m,x1=inf,yy1=inf,x2,y2,ans;
    char a[maxn][maxn];
    bool vis[maxn][maxn];
    inline int read()
    {
    	char c=getchar();int res=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    	return res*f;
    }
    struct cplx{double x,y;}A[maxm],B[maxm];
    cplx operator+(cplx a,cplx b){return (cplx){a.x+b.x,a.y+b.y};}
    cplx operator-(cplx a,cplx b){return (cplx){a.x-b.x,a.y-b.y};}
    cplx operator*(cplx a,cplx b){return (cplx){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
    int lim=1,len;
    int pos[maxm];
    inline void FFT(cplx* a,int op)
    {
    	for(int i=0;i<lim;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
    	for(int l=1;l<lim;l<<=1)
    	{
    		cplx wn=(cplx){cos(Pi/l),op*sin(Pi/l)};
    		for(int i=0;i<lim;i+=l<<1)
    		{
    			cplx w=(cplx){1,0};
    			for(int j=0;j<l;j++,w=w*wn)
    			{
    				cplx x=a[i+j],y=w*a[i+l+j];
    				a[i+j]=x+y;a[i+l+j]=x-y;
    			} 
    		}
    	}
    	if(op==1)return;
    	for(int i=0;i<lim;i++)a[i].x/=lim;
    }
    void bfs(int sx,int sy)
    {
    	queue<pii>q;
    	q.push(mkp(sx,sy));
    	vis[sx][sy]=0;
    	while(!q.empty())
    	{
    		pii now=q.front();q.pop();
    		int x=now.fir,y=now.sec;
    		A[(x-1)*m+y-1].x=1;
    		for(int i=0;i<4;i++)
    		{
    			int mx=x+dx[i],my=y+dy[i];
    			if(vis[mx][my])vis[mx][my]=0,q.push(mkp(mx,my));
    		}
    	}
    }
    int main()
    {
    	n=read(),m=read();
    	for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(a[i][j]=='o')x1=min(x1,i),yy1=min(yy1,j),x2=max(x2,i),y2=max(y2,j);
    			else if(a[i][j]=='#')A[n*m-(i-1)*m-j]=(cplx){1,0};
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=m;j++)
    			if(a[i][j]=='o')B[(i-x1)*m+j-yy1]=(cplx){1,0};
    	while(lim<n*m)lim<<=1,len++;
    	for(int i=0;i<lim;i++)pos[i]=(pos[i>>1]>>1)|((i&1)<<(len-1));
    	FFT(A,1);FFT(B,1);
    	for(int i=0;i<lim;i++)A[i]=A[i]*B[i];
    	FFT(A,-1);
    	for(int i=1;i<=n-(x2-x1);i++)
    		for(int j=1;j<=m-(y2-yy1);j++)
    			if(A[n*m-(i-1)*m-j].x<eps)vis[i][j]=1;
    	for(int i=0;i<lim;i++)A[i]=(cplx){0,0};
    	bfs(x1,yy1);
    	FFT(A,1);
    	for(int i=0;i<lim;i++)A[i]=A[i]*B[i];
    	FFT(A,-1);
    	for(int i=0;i<n*m;i++)if(A[i].x>eps)ans++;
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    Qt学习之系列[9] – QCoreApplication:processEvents()可能会引起递归,导致栈溢出崩溃
    Qt中利用QTime类来控制时间,这里简单介绍一下QTime的成员函数的用法:
    获取输入设备的vid和pid
    QProcess 进程类—调用外部程序
    Q_INVOKABLE与invokeMethod用法全解
    QML插件扩展2(基于C++的插件扩展)
    leetcode第一刷_Word Search
    设计模式之抽象工厂模式
    Python Random随机数
    【X240 QQ视频对方听不到声音】解决方法
  • 原文地址:https://www.cnblogs.com/nofind/p/12147686.html
Copyright © 2011-2022 走看看