残缺的字符串

题目描述

很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串 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]}-2\sum_{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\n",tot) ;
    for(int i = 1 ; i <= tot ; i ++) printf("%d ",pos[i]) ;
    return 0 ;
}
posted @ 2018-08-24 09:05  beretty  阅读(188)  评论(0编辑  收藏  举报