zoukankan      html  css  js  c++  java
  • LOJ6388:[THUPC2018]赛艇——题解

    https://loj.ac/problem/6388

    如果你做过BZOJ5217:[Lydsy2017省队十连测]航海舰队的话,那么恭喜你,这道题就是大水题。

    如果你做过BZOJ4259:残缺的字符串的话,那么基本的字符串匹配FFT也是能想到的。

    如果没做过的话,很抱歉,没有一定的套路的话这道题很难想(而对于我这样的蒟蒻来说就是没法想。)

    将行走路线看做一个地图b,走过的路为1,没走的为0.

    于是可以变成这张地图可以与原地图a匹配多少次(匹配成功在于两张图的1不能重叠。)

    按照BZOJ5217的套路,将二维压成一维,就变成了对于一个下标为p的点,不满足a[p+i]=1且b[i]=1。

    于是有f[i]=sigma(a[i+j]*b[j])=0,将a数组颠倒得f[i]=sigma(a[n*m-i-j]*b[j])=0是卷积,可以FFT运算。

    最后统计f[i]=0的个数即可。

    #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;
    const dl pi=acos(-1.0);
    const dl eps=0.5;
    const int M=1505;
    const int N=M*M*8;
    const int K=5e6+5;
    struct complex{
        dl x,y;
        complex(dl xx=0,dl yy=0){
        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=1,j=n>>1;i<n-1;i++){
        if(i<j)swap(a[i],a[j]);
        int k=n>>1;
        while(j>=k){j-=k;k>>=1;}
        if(j<k)j+=k;
        }
        for(int i=2;i<=n;i<<=1){
        complex res(cos(-2*on*pi/i),sin(-2*on*pi/i));
        for(int j=0;j<n;j+=i){
            complex w(1,0);
            for(int k=j;k<j+i/2;k++){
            complex u=a[k],t=w*a[k+i/2];
            a[k]=u+t;a[k+i/2]=u-t;
            w=w*res;
            }
        }
        }
        if(on==-1)
        for(int i=0;i<n;i++)a[i].x/=n;
    }
    bool tmp[M*2+10][M*2+10];
    int n,m,k;
    char mp[M][M],s[K];
    complex a[N],b[N];
    int main(){
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)scanf("%s",mp[i]+1);
    
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(mp[i][j]=='1')a[n*m-(i-1)*m-j]=complex(1,0);
        
        scanf("%s",s);
        int x=n,y=m;
        int x1=n,y1=m,x2=n,y2=m;
        tmp[x][y]=1;
        for(int i=0;i<k;i++){
            if(s[i]=='w')x--;
        if(s[i]=='a')y--;
            if(s[i]=='s')x++;
            if(s[i]=='d')y++;
        tmp[x][y]=1;
        x1=min(x1,x),y1=min(y1,y),x2=max(x2,x),y2=max(y2,y);
        }
        for(int i=x1;i<=x2;i++)
        for(int j=y1;j<=y2;j++)
            if(tmp[i][j])b[(i-x1)*m+j-y1]=complex(1,0);
    
        int len=1;
        while(len<n*m)len<<=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);
    
        int ans=0;
        for(int i=1;i<=n-(x2-x1);i++)
        for(int j=1;j<=m-(y2-y1);j++)
            if(a[n*m-(i-1)*m-j].x<eps)ans++;
        printf("%d
    ",ans);
        return 0;
    }

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

     +本文作者:luyouqi233。               +

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

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

  • 相关阅读:
    九连环
    杨辉三角
    魔术师发牌问题(循环链表)
    Linux 技巧:让进程在后台可靠运行的几种方法
    博客新地址
    x&(-x)取x的最后一个1的证明
    c++对象模型布局分析
    c++ 子类要正确的调用父类构造函数
    hibernate ID 生成方式
    IOCP
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9164223.html
Copyright © 2011-2022 走看看