• 残缺的字符串


    题目描述

    很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串 A 和 B ,其中 A 串长度为 m , B 串长度为 n 。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。

    你想对这两个串重新进行匹配,其中 A 为模板串,那么现在问题来了,请回答,对于 B 的每一个位置 i,从这个位置开始连续 m 个字符形成的子串是否可能与 A 串完全匹配?

    输入输出格式

    输入格式:

    第一行包含两个正整数 m , n ,分别表示 A 串和 B 串的长度。

    第二行为一个长度为 m 的字符串 A 。

    第三行为一个长度为 n 的字符串 B 。

    两个串均仅由小写字母和号组成,其中号表示相应位置已经残缺。

    输出格式:

    第一行包含一个整数 k ,表示 B 串中可以完全匹配 A 串的位置个数。

    若 k > 0 ,则第二行输出 k 个正整数,从小到大依次输出每个可以匹配的开头位置(下标从 1 开始)。

    输入输出样例

    输入样例#1:

    3 7
    a * b
    aebr * ob

    输出样例#1:

    2
    1 5

    说明

    100 %的数据满足 (n <= m <= 300000)


    震惊,FFT竟然干出这种事

    我是找FFT题找到这道题的

    但是瞅了半天没看出来咋FFT ==

    觉得咋看咋像KMP之类的东西

    看了题解深入思考

    发现肥肠的妙

    然后我们把*的权值设置成0,其他的就随便设个权值就好了

    然后我们可以构造一个函数(E[i]),表示在B串中结尾为i是否能完整的匹配A串

    所以(E[i] = sum_{j=1}^{m}{(A[m-j+1]-y[i-j+1])^2A[m-j+1]B[i-j+1]})

    但是这玩意儿并不能卷积==

    所以我们把还是把A串翻转过来

    这样(E[i] = sum_{j=1}^{m}{(revA[j]-B[i-j+1)^2revA[j]B[i-j+1]})

    然后我们再把各项都拆开,式子就成了

    (E[i] = sum_{j=1}^{m}{revA[j]^3B[i-j+1]}-2sum_{j=1}^{m}{revA[j]^2B[i-j+1]^2}+sum_{j=1}^{m}{revA[j]B[i-j+1]^3})

    然后我们就分别对三段卷积就好辣

    但是注意卷积后第i+1项代表的是E[i]

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std ;
    const int M = 1500005 ;
    const double eps = 1e-8 ;
    const double Pi = acos(-1.0) ;
    
    struct Complex {
    	double x , y ;
    	Complex (double Tx = 0 , double Ty = 0) { x = Tx , y = Ty ;}
    }a[M] , b[M] ;
    Complex operator + (Complex a , Complex b) {
    	return Complex (a.x + b.x , a.y + b.y) ;
    }
    Complex operator - (Complex a , Complex b) {
    	return Complex (a.x - b.x , a.y - b.y) ;
    }
    Complex operator * (Complex a , Complex b) {
    	return Complex (a.x * b.x - a.y * b.y , a.x * b.y + a.y * b.x) ;
    }
    char s[M] ;
    int n , m ;
    int l , r[M] , digital = 1 ;
    int x[M] , y[M] , tot , pos[M] ;
    double Ans[M] ;
    inline void FFT(Complex *A , int unit) {
    	for(int i = 0 ; i < digital ; i ++) 
    	  if(r[i] > i)
    	    swap(A[i] , A[r[i]]) ;
    	for(int mid = 1 ; mid < digital ; (mid <<= 1)) {
    		Complex W (cos(Pi / mid) , unit * sin(Pi / mid)) ;
    		int R = (mid << 1) ;
    		for(int j = 0 ; j < digital ; j += R) {
    			Complex w(1 , 0) ;
    			for(int k = 0 ; k < mid ; k ++ , w = w * W) {
    				Complex x = A[j + k] , y = w * A[j + k + mid] ;
    				A[j + k] = x + y ; A[j + k + mid] = x - y ;
    			}
    		}
    	}
    }
    inline void Solve() {
    	while(digital <= n + m) digital <<= 1 , l ++ ;
    	for(int i = 0 ; i < digital ; i ++) 
    	  r[i] = (r[i>>1]>>1) | ((i&1)<<(l - 1)) ;
    	FFT(a , 1) ; FFT(b , 1) ;
    	for(int i = 0 ; i <= digital ; i ++) a[i] = a[i] * b[i] ;
    	FFT(a , -1) ;
    }
    inline void Clear() {
    	memset(a , 0 , sizeof(a)) ;
    	memset(b , 0 , sizeof(b)) ;
    	digital = 1 ; l = 0 ;
    }
    int main() {
    	scanf("%d%d",&m,&n) ;
    	scanf("%s",s + 1) ;
    	for(int i = 1 ; i <= m ; i ++) {
    		if(s[i] == '*') x[i] = 0 ; 
    		else x[i] = s[i] - 'a' + 1 ;
    	}
    	scanf("%s",s + 1) ;
    	for(int i = 1 ; i <= n ; i ++) {
    		if(s[i] == '*') y[i] = 0 ;
    		else y[i] = s[i] - 'a' + 1 ;
    	}
    	for(int i = 1 ; i <= (m>>1) ; i ++) swap(x[i] , x[m - i + 1]) ;
    	++ m ; ++ n ;
        for(int i = 1 ; i <= m ; i ++) a[i].x = x[i] * x[i] * x[i] ;
        for(int i = 1 ; i <= n ; i ++) b[i].x = y[i] ;
        Solve() ;
        for(int i = m ; i <= n ; i ++) Ans[i] += (a[i].x / digital) ;
        Clear() ;
        for(int i = 1 ; i <= m ; i ++) a[i].x = x[i] * x[i] ;
        for(int i = 1 ; i <= n ; i ++) b[i].x = y[i] * y[i] ;
        Solve() ;
        for(int i = m ; i <= n ; i ++) Ans[i] -= 2 * (a[i].x / digital) ;
        Clear() ;
        for(int i = 1 ; i <= m ; i ++) a[i].x = x[i] ;
        for(int i = 1 ; i <= n ; i ++) b[i].x = y[i] * y[i] * y[i] ;
        Solve() ;
        for(int i = m ; i <= n ; i ++) Ans[i] += (a[i].x / digital) ;
        for(int i = m ; i <= n ; i ++)
          if(abs(Ans[i]) <= eps)
            pos[++tot] = i - m + 1 ;
        printf("%d
    ",tot) ;
        for(int i = 1 ; i <= tot ; i ++) printf("%d ",pos[i]) ;
        return 0 ;
    }
    
  • 相关阅读:
    Rotate Image,N*N矩阵顺时针旋转90度
    JumpGame,JumpGame2
    WildcardMatching和Regex,通配符匹配和正则表达式匹配
    Multiply Strings,字符串相乘
    TrappingRainWater
    300万PV的ASP.NET网站使用阿里云的配置建议
    java 学习 安卓学习
    如何学习Yii
    Lemon开源OA
    JAVA-进行Java Web项目开发需要掌握的技术
  • 原文地址:https://www.cnblogs.com/beretty/p/9527802.html
Copyright © 2020-2023  润新知