• URAL1966 Cipher Message 3


    题目描述

    题解:

    能看出来的是,每一组数只能改最后一位,所以前$7$位动不了。

    所以$KMP$跑一跑。

    重点在于最后一位怎么搞。

    如果$KMP$跑完了还没找到合适的位置,直接$puts("No")$就好了。

    剩下个匹配问题。

    (要不是数据范围拦着我我都想建图跑费用流了)

    这个匹配可以用$FFT$求。

    $FFT$不是求$sum(a[i]*b[j-i])$的吗?怎么求字符串匹配?

    其实我们只想要最后多项式中某一位上的值,所以$b[j-i]$和$b[i]$没有区别,反转数组就好了。

    我们要求的是需要多少个$0$变成$1$,以及多少个$1$变成$0$。

    所以$FFT$求两遍卷积,第一次$a[i]=[s1[i]==0],b[i]=[s2[i]==1]$,注意这里的$b$还没有反转。

    第二次反过来就可以了。

    代码:

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef unsigned long long ull;
    const int N = 270050;
    const ull seed = 131;
    const double Pi = acos(-1.0);
    template<typename T>
    inline void read(T&x)
    {
        T f = 1,c = 0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
        x = f*c;
    }
    struct cp
    {
        double x,y;
        cp(){}
        cp(double x,double y):x(x),y(y){}
        cp operator + (const cp&a)const{return cp(x+a.x,y+a.y);}
        cp operator - (const cp&a)const{return cp(x-a.x,y-a.y);}
        cp operator * (const cp&a)const{return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
    };
    int to[4*N],lim=1,l;
    void fft(cp *a,int len,int k)
    {
        for(int i=0;i<len;i++)
            if(i<to[i])swap(a[i],a[to[i]]);
        for(int i=1;i<len;i<<=1)
        {
            cp w0(cos(Pi/i),k*sin(Pi/i));
            for(int j=0;j<len;j+=(i<<1))
            {
                cp w(1,0);
                for(int o=0;o<i;o++,w=w*w0)
                {
                    cp w1 = a[j+o],w2 = a[j+o+i]*w;
                    a[j+o] = w1+w2;
                    a[j+o+i] = w1-w2;
                }
            }
        }
        if(k==-1)
            for(int i=0;i<len;i++)
                a[i].x/=len;
    }
    void rd(int n,int *a1,int *a2)
    {
        for(int x,i=1;i<=n;i++)
        {
            read(x);
            a1[i] = x%10;
            a2[i] = x/10;
        }
    }
    int n,m,a[2][N],b[2][N];
    bool vis[N];
    int ans[N];
    cp c1[4*N],c2[4*N],c3[4*N];
    int nxt[N];
    void get_nxt(int *a,int len)
    {
        int i = 1,j = 0;
        while(i<=len)
        {
            if(!j||a[i]==a[j])
            {
                i++,j++;
                nxt[i] = j;
            }else j = nxt[j];
        }
    }
    int kmp(int *a,int la,int *b,int lb)
    {
        int ret = 0;
        int i = 1,j = 1;
        while(i<=la)
        {
            if(a[i]==b[j]||j==0)
            {
                i++,j++;
                if(j==lb+1)
                {
                    vis[i-1]=1;
                    j = nxt[j];
                    ret = 1;
                }
            }else j=nxt[j];
        }
        return ret;
    }
    void work()
    {
        fft(c1,lim,1),fft(c2,lim,1);
        for(int i=0;i<lim;i++)c3[i]=c1[i]*c2[i];
        fft(c3,lim,-1);
    }
    void init()
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(ans,0,sizeof(ans));
        memset(vis,0,sizeof(vis));
        lim=1,l=0;
    }
    int main()
    {
    //    freopen("tt.in","r",stdin);
        while(scanf("%d%d",&n,&m)>0)
        {
        init();
        rd(n,a[0],a[1]),rd(m,b[0],b[1]);
        get_nxt(b[1],m);
        if(!kmp(a[1],n,b[1],m))
        {
            puts("No");
            continue;
        }
        puts("Yes");
        while(lim<2*(n+m))lim<<=1,l++;
        for(int i=1;i<lim;i++)to[i]=((to[i>>1]>>1)|((i&1)<<(l-1)));
        for(int i=0;i<lim;i++)c1[i]=c2[i]=cp(0,0);
        for(int i=0;i<n;i++)c1[i].x=(a[0][i+1]==1);
        for(int i=0;i<m;i++)c2[i].x=(b[0][m-i]==0);
        work();
        for(int i=0;i<n;i++)ans[i+1]=(int)(c3[i].x+0.5);
        for(int i=0;i<lim;i++)c1[i]=c2[i]=cp(0,0);
        for(int i=0;i<n;i++)c1[i].x=(a[0][i+1]==0);
        for(int i=0;i<m;i++)c2[i].x=(b[0][m-i]==1);
        work();
        for(int i=0;i<n;i++)ans[i+1]+=(int)(c3[i].x+0.5);
        int mn = N,pos=0;
        for(int i=m;i<=n;i++)
            if(vis[i]&&ans[i]<mn)
            {
                mn = ans[i];
                pos = i-m+1;
            }
        printf("%d %d
    ",mn,pos);
        }
        return 0;
    }
  • 相关阅读:
    OpenCV中threshold函数的使用
    opencv中namedWindow( )函数
    Open CV leaning
    RGB颜色表
    visual studio 2015 Opencv4.0.1配置
    uint16_t
    Arduino重置-复位问题
    bzoj1823 [JSOI2010]满汉全席(2-SAT)
    bzoj2208 [Jsoi2010]连通数(scc+bitset)
    UVAlive3713 Astronauts(2-SAT)
  • 原文地址:https://www.cnblogs.com/LiGuanlin1124/p/10284184.html
Copyright © 2020-2023  润新知