• luogu4173 残缺的字符串


    对于一类带有通配符的字符串匹配问题,我们考虑构造匹配函数,通过匹配函数的值来判断匹配的位置。

    先考虑一个不带通配符的问题:给定两个字符串(A,B),判断(B)的哪些位置能与(A)匹配。

    除了kmp,我们同样可以考虑构造匹配函数来解决匹配问题,首先将(A)串翻转同时在其末尾补(0),构造函数(f_i=sum_{j=0}^i(A_j-B_{i-j})^2),那么(B)中在第(i)个位置结尾的长度为(|A|)的子串能与(A)匹配当且仅当(f_i=0)。将函数展开后得到(sum_{j=0}^i(A_j^2-2A_jB_{i-j}+B_{i-j}^2)),只需要一次FFT便能得到结果。

    现在考虑有通配符的情况,那么原来对匹配函数的定义显然是不完备的,考虑第(i)位有通配符时直接算作匹配,故可以在第(i)位为通配符时令(A_i=0),那么便可将匹配函数的定义完善为(f_i=sum_{j=0}^i(A_j-B_{i-j})^2A_jB_{i-j}).

    展开后得到(f_i=sum_{j=0}^i(A_j^3B_{i-j}-2A_j^2B_{i-j}^2+A_jB_{i-j}^3)).

    做三次多项式乘法即可。

    #include<iostream>
    #include<string.h>
    #include<string>
    #include<stdio.h>
    #include<algorithm>
    #include<vector>
    #include<bitset>
    #include<math.h>
    #include<stack>
    #include<queue>
    #include<set>
    #include<map>
    using namespace std;
    typedef long long ll;
    typedef long double db;
    typedef pair<int,int> pii;
    const int N=300000+100;
    const db pi=acos(-1.0);
    #define lowbit(x) (x)&(-x)
    #define sqr(x) (x)*(x)
    #define rep(i,a,b) for (register int i=a;i<=b;i++)
    #define per(i,a,b) for (register int i=a;i>=b;i--)
    #define go(u,i) for (register int i=head[u];i;i=sq[i].nxt)
    #define fir first
    #define sec second
    #define mp make_pair
    #define pb push_back
    #define maxd 998244353
    #define eps 1e-8
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
        while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
        return x*f;
    }
    
    namespace My_Math{
    	#define N 100000
    
    	int fac[N+100],invfac[N+100];
    
    	int add(int x,int y) {return x+y>=maxd?x+y-maxd:x+y;}
    	int dec(int x,int y) {return x<y?x-y+maxd:x-y;}
    	int mul(int x,int y) {return 1ll*x*y%maxd;}
    	ll qpow(ll x,int y)
    	{
    		ll ans=1;
    		while (y)
    		{
    			if (y&1) ans=mul(ans,x);
    			x=mul(x,x);y>>=1;
    		}
    		return ans;
    	}
    	int inv(int x) {return qpow(x,maxd-2);}
    
    	int math_init()
    	{
    		fac[0]=invfac[0]=1;
    		rep(i,1,N) fac[i]=mul(fac[i-1],i);
    		invfac[N]=inv(fac[N]);
    		per(i,N-1,1) invfac[i]=mul(invfac[i+1],i+1);
    	}
    	#undef N
    }
    using namespace My_Math;
    
    namespace polynomial{
    	struct complex{
    		double x,y;
    		complex (double _x=0.0,double _y=0.0) {x=_x;y=_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);}
    	complex operator *(complex a,complex b) {return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    	
    	int r[N<<2];
    	void calcr(int &lim,int len)
    	{
    		lim=1;int cnt=0;
    		while (lim<len) {lim<<=1;cnt++;}
    		rep(i,0,lim-1) 
    			r[i]=(r[i>>1]>>1)|((i&1)<<(cnt-1));
    	}
    	
    	void fft(int lim,complex *a,int typ)
    	{
    		rep(i,0,lim-1)
    			if (i<r[i]) swap(a[i],a[r[i]]);
    		for (int mid=1;mid<lim;mid<<=1)
    		{
    			complex wn=complex(cos(pi/mid),sin(pi/mid)*typ);
    			int len=(mid<<1);
    			for (int sta=0;sta<lim;sta+=len)
    			{
    				complex w=complex(1,0);
    				for (int j=0;j<mid;j++,w=w*wn)
    				{
    					complex x=a[j+sta],y=a[j+sta+mid]*w;
    					a[j+sta]=x+y;a[j+sta+mid]=x-y;
    				}
    			}
    		}
    		if (typ==-1)
    			rep(i,0,lim-1) a[i].x/=lim;
    	}
    }
    using namespace polynomial;
    complex A[N<<2],B[N<<2],C[N<<2],emp=complex(0,0);
    int a[N],b[N],n,m;
    char s[N];
    vector<int> ans;
    
    int main()
    {
    	n=read();m=read();
    	scanf("%s",s);
    	rep(i,0,n-1) 
    		if (s[i]!='*') a[i]=s[i]-'a'+1;
    	reverse(a,a+n);
    	scanf("%s",s);
    	rep(i,0,m-1) 
    		if (s[i]!='*') b[i]=s[i]-'a'+1;
    	int lim=0;
    	calcr(lim,m*2);
    	rep(i,0,n-1) A[i]=complex(a[i]*a[i]*a[i],0);
    	rep(i,0,m-1) B[i]=complex(b[i],0);
    	fft(lim,A,1);fft(lim,B,1);
    	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
    	rep(i,0,lim-1) A[i]=B[i]=emp;
    	rep(i,0,n-1) A[i]=complex(a[i]*a[i],0);
    	rep(i,0,m-1) B[i]=complex(b[i]*b[i],0);
    	fft(lim,A,1);fft(lim,B,1);
    	rep(i,0,lim-1) C[i]=C[i]-A[i]*B[i]*2;
    	rep(i,0,lim-1) A[i]=B[i]=emp;
    	rep(i,0,n-1) A[i]=complex(a[i],0);
    	rep(i,0,m-1) B[i]=complex(b[i]*b[i]*b[i],0);
    	fft(lim,A,1);fft(lim,B,1);
    	rep(i,0,lim-1) C[i]=C[i]+A[i]*B[i];
    	fft(lim,C,-1);
    	rep(i,n-1,m-1)
    		if (fabs(C[i].x)+0.5<1) ans.pb(i-n+2);
    	int len=ans.size();
    	printf("%d
    ",len);
    	rep(i,0,len-1) printf("%d ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    聊聊自定义实现的SPI如何与spring进行整合
    聊聊读源码这件事
    聊聊自定义SPI如何使用自定义标签注入到spring容器中
    聊聊如何自定义数据脱敏
    聊聊自定义SPI如何与sentinel整合实现熔断限流
    排查not eligible for getting processed by all BeanPostProcessors
    SqlServer 数据脱敏脚本
    WPF 窗体使用 Show() 单个显示并设置弹窗相对于主窗体位置
    【SQLite】获取插入 ID 的几种方式
    Winform DataGridView 行单元格增加自定义 ToolTip
  • 原文地址:https://www.cnblogs.com/encodetalker/p/12387381.html
Copyright © 2020-2023  润新知