• 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
    ",ans);
      return 0;
    }
    
    
  • 相关阅读:
    GyPSii API PHP应用初探
    无缝滚动图片的一个简单封装
    Linux设置固定IP
    DIV卷帘效果示例
    vsftp安装配置
    PHP判断FORM来的数据是否为整数
    Linux下设置apache开机启动
    从Discuz提取的数据库和模板操作文件,很容易使用哦
    discuz 表情的提取
    IE6、IE7浮动层被下面的动挡住的问题
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8909876.html
Copyright © 2020-2023  润新知