• 【洛谷P4173】残缺的字符串


    题目

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

    思路

    给每一个字母一个权值,那么一个区间 ([l,r]) 如果可以匹配,那么必然满足

    [sum^{r}_{i=l}a_ib_i(a_i-b_i)^2=0 ]

    (f_i) 表示位置 (i) 的权值(也就是如果上式 (l=i,r=i+n-1)),那么有

    [f_i=sum^{n}_{j=1}a_jb_{i+j-1}(a_j-b_{i+j-1})^2 ]

    不难想到把 (a) 逆序,拆开括号,并且把 (a_{n+1sim m}) 设为 (0)

    [f_{m-i}=sum^{m}_{j=1}a_{m-j}^3b_{i+j}+sum^{m}_{j=1}a_{m-j}b^3_{i+j}-sum^{m}_{j=1}2a_{m-j}^2b_{i+j}^2 ]

    跑三次 FFT 即可。常数较大,开 O2 才过。
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    #define cp complex<double>
    using namespace std;
    
    const int N=1050000;
    const double eps=0.5,pi=acos(-1);
    int n,m,lim,a[N],b[N],rev[N];
    cp f[N],g[N],h[3][N];
    char s[N],t[N];
    queue<int> qans;
    int c[N];
    
    void FFT(cp *f,int tag)
    {
    	for (int i=0;i<lim;i++)
    		if (i<rev[i]) swap(f[i],f[rev[i]]);
    	for (int k=1;k<lim;k<<=1)
    	{
    		cp tmp(cos(pi/k),tag*sin(pi/k));
    		for (int i=0;i<lim;i+=(k<<1))
    		{
    			cp w(1,0);
    			for (int j=0;j<k;j++,w=w*tmp)
    			{
    				cp x=f[i+j],y=w*f[i+j+k];
    				f[i+j]=x+y; f[i+j+k]=x-y;
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%s%s",&n,&m,s+1,t+1);
    	for (int i=1;i<=n;i++) a[i]=(s[i]-'a'+1)*(s[i]!='*');
    	for (int i=1;i<=m;i++) b[i]=(t[i]-'a'+1)*(t[i]!='*');
    	reverse(a+1,a+1+m);
    	lim=1;
    	while (lim<=2*m) lim<<=1;
    	for (int i=0;i<lim;i++)
    		rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
    	
    	for (int i=0;i<lim;i++)
    	{
    		f[i]=cp(1.0*a[i]*a[i]*a[i],0);
    		g[i]=cp(1.0*b[i],0);
    	}
    	FFT(f,1); FFT(g,1);
    	for (int i=0;i<lim;i++) h[0][i]=f[i]*g[i];
    	FFT(h[0],-1);
    	
    	for (int i=0;i<lim;i++)
    	{
    		f[i]=cp(1.0*a[i],0);
    		g[i]=cp(1.0*b[i]*b[i]*b[i],0);
    	}
    	FFT(f,1); FFT(g,1);
    	for (int i=0;i<lim;i++) h[1][i]=f[i]*g[i];
    	FFT(h[1],-1);
    	
    	for (int i=0;i<lim;i++)
    	{
    		f[i]=cp(2.0*a[i]*a[i],0);
    		g[i]=cp(1.0*b[i]*b[i],0);
    	}
    	FFT(f,1); FFT(g,1);
    	for (int i=0;i<lim;i++) h[2][i]=f[i]*g[i];
    	FFT(h[2],-1);
    	
    	for (int i=1;i<=m-n+1;i++)
    		if (fabs((h[0][m+i].real()+h[1][m+i].real()-h[2][m+i].real())/lim)<eps)
    			qans.push(i);
    	printf("%d
    ",qans.size());
    	for (;qans.size();qans.pop())
    		printf("%d ",qans.front());
    	return 0;
    }
    
  • 相关阅读:
    谷歌浏览器调试按钮作用
    Android App罕见错误和优化方案
    cordova插件iOS平台实战开发注意点
    xcode8继续愉快的使用插件
    答CsdnBlogger问-关于VR取代安卓的问题
    答CsdnBlogger问-关于职业发展和团队管理问题
    答CsdnBlogger问-关于安卓入行和开发问题
    答CsdnBlogger问-关于定时和后台服务问题
    下载大图的demo by apple,值得研究和参考
    一个不错的mac软件下载站,mark一下 (商业使用请务必支持正版)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14254912.html
Copyright © 2020-2023  润新知