zoukankan      html  css  js  c++  java
  • 【bzoj4259/bzoj4503】残缺的字符串/两个串 FFT

    bzoj4259

    题目描述

    很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
    你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?

    输入

    第一行包含两个正整数m,n(1<=m<=n<=300000),分别表示A串和B串的长度。
    第二行为一个长度为m的字符串A。
    第三行为一个长度为n的字符串B。
    两个串均仅由小写字母和*号组成,其中*号表示相应位置已经残缺。

    输出

    第一行包含一个整数k,表示B串中可以完全匹配A串的位置个数。
    若k>0,则第二行输出k个正整数,从小到大依次输出每个可以匹配的开头位置(下标从1开始)。

    样例输入

    3 7
    a*b
    aebr*ob

    样例输出

    2
    1 5


    bzoj4503

    题目描述

    几乎同上,只是B串中不含万能字符,更简单些。

    题解

    FFT

    设两个字符c1、c2的差异度为(c1-c2)^2,那么两个普通字符串能匹配,当且仅当∑(str1[i]-str2[i])^2=0

    考虑包含万能字符的情况,由于可以匹配任何字符,则应当把差异度看作0。

    即:万能字符为0,其它字符为1~26,差异度为c1*c2*(c1-c2)^2。

    展开得c1^3*c2 - 2*c1^2*c2^2 + c1*c2^3。

    令题中所给的两个字符串计算差异度,可以分成以上3部分来求,并且每部分都可以化成只包含str1和只包含str2的两个式子的乘积。

    并且发现两个位置的差是定值,可以翻转后转化为卷积来求。

    于是上FFT出解。

    对于4503,可以少考虑一种一个字符为万能字符的情况,所以可以少FFT计算,具体见代码。

    bzoj4259:

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #define N 1 << 20
    #define pi acos(-1)
    #define tra(ch) (ch == '*' ? 0 : ch - 'a' + 1)
    using namespace std;
    struct data
    {
    	double x , y;
    	data() {x = y = 0;}
    	data(double x0 , double y0) {x = x0 , y = y0;}
    	data operator+(const data a)const {return data(x + a.x , y + a.y);}
    	data operator-(const data a)const {return data(x - a.x , y - a.y);}
    	data operator*(const data a)const {return data(x * a.x - y * a.y , x * a.y + y * a.x);}
    }a1[N] , b1[N] , a2[N] , b2[N] , a3[N] , b3[N];
    char sa[N] , sb[N];
    int ans[N] , tot;
    void fft(data *a , int n , int flag)
    {
    	int i , j , k;
    	for(i = k = 0 ; i < n ; i ++ )
    	{
    		if(i > k) swap(a[i] , a[k]);
    		for(j = (n >> 1) ; (k ^= j) < j ; j >>= 1);
    	}
    	for(k = 2 ; k <= n ; k <<= 1)
    	{
    		data wn(cos(2 * pi * flag / k) , sin(2 * pi * flag / k));
    		for(i = 0 ; i < n ; i += k)
    		{
    			data t , w(1 , 0);
    			for(j = i ; j < i + (k >> 1) ; j ++ , w = w * wn)
    				t = w * a[j + (k >> 1)] , a[j + (k >> 1)] = a[j] - t , a[j] = a[j] + t;
    		}
    	}
    }
    void work(data *a , data *b , int len)
    {
    	int i;
    	fft(a , len , 1) , fft(b , len , 1);
    	for(i = 0 ; i < len ; i ++ ) a[i] = a[i] * b[i];
    	fft(a , len , -1);
    	for(i = 0 ; i < len ; i ++ ) a[i].x = a[i].x / len;
    }
    int main()
    {
    	int m , n , i , len;
    	double tmp;
    	scanf("%d%d%s%s" , &m , &n , sa , sb);
    	for(i = 0 ; i < m ; i ++ ) tmp = tra(sa[i]) , a1[m - i - 1].x = tmp , a2[m - i - 1].x = tmp * tmp , a3[m - i - 1].x = tmp * tmp * tmp;
    	for(i = 0 ; i < n ; i ++ ) tmp = tra(sb[i]) , b1[i].x = tmp * tmp * tmp , b2[i].x = tmp * tmp , b3[i].x = tmp;
    	for(len = 1 ; len < n + m ; len <<= 1);
    	work(a1 , b1 , len) , work(a2 , b2 , len) , work(a3 , b3 , len);
    	for(i = 0 ; i <= n - m ; i ++ )
    		if(!(int)(a1[i + m - 1].x - 2 * a2[i + m - 1].x + a3[i + m - 1].x + 0.1))
    			ans[++tot] = i;
    	printf("%d
    " , tot);
    	for(i = 1 ; i <= tot ; i ++ ) printf("%d " , ans[i] + 1);
    	return 0;
    }
    

    bzoj4503:

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #define N 1 << 20
    #define tra(ch) (ch == '?' ? 0 : ch - 'a' + 1)
    #define pi acos(-1)
    using namespace std;
    struct data
    {
    	double x , y;
    	data() {x = y = 0;}
    	data(double x0 , double y0) {x = x0 , y = y0;}
    	data operator+(const data a)const {return data(x + a.x , y + a.y);}
    	data operator-(const data a)const {return data(x - a.x , y - a.y);}
    	data operator*(const data a)const {return data(x * a.x - y * a.y , x * a.y + y * a.x);}
    }a1[N] , b1[N] , a2[N] , b2[N];
    char sa[N] , sb[N];
    int ans[N] , tot;
    void fft(data *a , int n , int flag)
    {
    	int i , j , k;
    	for(i = k = 0 ; i < n ; i ++ )
    	{
    		if(i > k) swap(a[i] , a[k]);
    		for(j = (n >> 1) ; (k ^= j) < j ; j >>= 1);
    	}
    	for(k = 2 ; k <= n ; k <<= 1)
    	{
    		data wn(cos(2 * pi * flag / k) , sin(2 * pi * flag / k));
    		for(i = 0 ; i < n ; i += k)
    		{
    			data t , w(1 , 0);
    			for(j = i ; j < i + (k >> 1) ; j ++ , w = w * wn)
    				t = w * a[j + (k >> 1)] , a[j + (k >> 1)] = a[j] - t , a[j] = a[j] + t;
    		}
    	}
    }
    void work(data *a , data *b , int len)
    {
    	int i;
    	fft(a , len , 1) , fft(b , len , 1);
    	for(i = 0 ; i < len ; i ++ ) a[i] = a[i] * b[i];
    	fft(a , len , -1);
    	for(i = 0 ; i < len ; i ++ ) a[i].x /= len;
    }
    int main()
    {
    	int la , lb , i , len;
    	double tmp , a3 = 0;
    	scanf("%s%s" , sa , sb) , la = strlen(sa) , lb = strlen(sb);
    	for(i = 0 ; i < la ; i ++ ) tmp = tra(sa[i]) , a1[i].x = tmp * tmp , a2[i].x = tmp;
    	for(i = 0 ; i < lb ; i ++ ) tmp = tra(sb[i]) , b1[lb - i - 1].x = tmp , b2[lb - i - 1].x = tmp * tmp , a3 += tmp * tmp * tmp;
    	for(len = 1 ; len < 2 * la || len < 2 * lb ; len <<= 1);
    	work(a1 , b1 , len) , work(a2 , b2 , len);
    	for(i = 0 ; i < la - lb + 1 ; i ++ )
    		if(!(int)(a1[i + lb - 1].x - 2 * a2[i + lb - 1].x + a3 + 0.1))
    			ans[++tot] = i;
    	printf("%d
    " , tot);
    	for(i = 1 ; i <= tot ; i ++ ) printf("%d
    " , ans[i]);
    	return 0;
    }
    

     

     

  • 相关阅读:
    ES学习(十)
    ES学习(九)
    ES学习(八)
    ES学习(七)--documentAPI
    ES学习(六)--shard和replica机制
    ES学习(四)--嵌套聚合、下钻分析、聚合分析
    uniapp中常见的请求方法封装 --来之插件市场(全局方法封装(请求/正则/URI)
    工具/插件
    express中文件的上传 multer
    express中开发常用
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6878821.html
Copyright © 2011-2022 走看看