【题解】2021HDU多校第三场 HDU6975 Forgiving matching

2021HDU多校第三场 HDU6975 Forgiving matching

题意

给一个串\(A\),和串\(B\)(均仅含字符'1'-'9'或通配符'*'),其中通配符可以匹配任意字符,分别求出最多容许\(k\)个字符失配的情况下(\(0\le k\le m\)),有多少个\(A\)的子串和\(B\)匹配。

\(1\le |B|\le |A|\le 2\times 10^5,\sum|A|\le 10^6\)

题解

做法类似于Fuzzy search。两个字符匹配当且仅当它们字符相等,或者至少有一个是通配符。由于需要求出\(A\)中每个长度为\(m\)的子串有多少个位置与\(B\)串匹配,我们可以对每个字符分开处理.对于数字字符\(c\),我们将\(A,B\)中为\(c\)的位置置为1,其他位置置为0,翻转\(B\)串后做\(FFT\),则\(a_i\)即为\(A\)中以\(i\)结尾的长度为\(m\)的子串有多少个位置的\(c\)字符和\(B\)串对应位置的\(c\)字符匹配。对于通配符,通过通配符匹配的位置数即为\(A的长度为m的子串中通配符的个数+B中通配符的个数-对应位置都是通配符的个数\),将上述两种情况相加后即得到\(A\)中每个长度为\(m\)的子串有多少个位置与\(B\)串匹配,即可求答案。

#include <bits/stdc++.h>
typedef double db;
typedef long long ll;
using namespace std;
const double pi=acos(-1.0);
const int N=2300005;
int r[N];
struct cpl{
	db x,y;
	cpl operator +(const cpl & bb)const{return (cpl){x+bb.x,y+bb.y};}
	cpl operator -(const cpl & bb)const{return (cpl){x-bb.x,y-bb.y};}
	cpl operator *(const cpl & bb)const{return (cpl){x*bb.x-y*bb.y,x*bb.y+y*bb.x};}
	cpl operator /(const db &bb)const{return (cpl){x/bb,y/bb};}
}a[N],b[N];
void fft(cpl *a,int lim,int typ){
	for(int i=0;i<=lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
	for(int mid=1;mid<lim;mid<<=1){
		cpl w1=(cpl){cos(pi/mid),typ*sin(pi/mid)};
		for(int  R=mid<<1,j=0;j<lim;j+=R){
			cpl w=(cpl){1,0};
			for(int i=0;i<mid;i++,w=w*w1){
				cpl y=a[i+j+mid]*w;
				a[i+j+mid]=a[i+j]-y;a[i+j]=a[i+j]+y;
			}
		}
	}
	if(typ==-1){
		for(int i=0;i<=lim;i++)a[i].x/=lim;
		for(int i=0;i<=lim;i++)a[i].y/=lim;
	}
}
int lim=0,l=0,n,m;
int f[N],s1[N],s2[N],ans[N];
void f1(){
	string A,B;
	cin>>n>>m;
	cin>>A>>B;
	s1[0]=(A[0]=='*');s2[0]=(B[0]=='*');
	for(int i=0;i<=n;i++){f[i]=0;ans[i]=0;}
	for(int i=1;i<n;i++){s1[i]=s1[i-1]+(A[i]=='*');}
	for(int i=1;i<m;i++){s2[i]=s2[i-1]+(B[i]=='*');ans[i]=0;}
	lim=1;l=0;while(lim<=(n+m)){lim<<=1;++l;}
	for(int i=0;i<lim;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	for(int o=0;o<10;o++){
		char c='0'+o;
		for(int i=0;i<=lim;i++){a[i].x=a[i].y=0;b[i].x=b[i].y=0;}
		for(int i=0;i<n;i++){
			if(A[i]==c){a[i].x=1;}
		}
		for(int i=0;i<m;i++){
			if(B[i]==c){a[m-1-i].y=1;}
		}
		fft(a,lim,1);
		for(int i=0;i<=lim;i++){a[i]=a[i]*a[i];}
		fft(a,lim,-1);
		for(int i=m-1;i<n;i++){f[i]+=(int)(0.5+a[i].y/2.0);}
	}
	
	{ //处理通配符 
		char c='*';
		for(int i=0;i<=lim;i++){a[i].x=a[i].y=0;b[i].x=b[i].y=0;}
		for(int i=0;i<n;i++){
			if(A[i]==c){a[i].x=1;}
		}
		for(int i=0;i<m;i++){
			if(B[i]==c){a[m-1-i].y=1;}
		}
		fft(a,lim,1);
		for(int i=0;i<=lim;i++){a[i]=a[i]*a[i];}
		fft(a,lim,-1);
		int ns=s2[m-1];
		for(int i=m-1;i<n;i++){
			if(i==m-1){
				f[i]+=s1[i]+ns-(int)(0.5+a[i].y/2.0);
			}
			else{
				f[i]+=s1[i]-s1[i-m]+ns-(int)(0.5+a[i].y/2.0);
			}
		}
	} 
	for(int i=m-1;i<n;i++){
		ans[m-f[i]]++;
	}
	for(int i=1;i<=m;i++){
		ans[i]+=ans[i-1];
	}
	for(int i=0;i<=m;i++){
		cout<<ans[i]<<"\n";
	}
}
int main(){
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	int t;cin>>t;
	while(t--)
		f1();
	return 0;
}

posted @ 2021-07-29 14:04  bobh  阅读(78)  评论(0编辑  收藏  举报