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;
    }
    

     

     

  • 相关阅读:
    剑指 Offer——13. 调整数组顺序使奇数位于偶数前面
    剑指 Offer——3. 从尾到头打印链表
    剑指 Offer——2. 替换空格
    剑指 Offer——1. 二维数组中的查找
    LeetCode 905. Sort Array By Parity 按奇偶校验排列数组
    LeetCode 448. Find All Numbers Disappeared in an Array找到所有数组中消失的元素
    SSH 代码笔记
    anaconda3安装caffe
    opencv多版本安装
    人脸文章与数据库
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6878821.html
Copyright © 2011-2022 走看看