zoukankan      html  css  js  c++  java
  • 【刷题】BZOJ 4503 两个串

    Description

    兔子们在玩两个串的游戏。给定两个字符串S和T,兔子们想知道T在S中出现了几次,

    分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。

    Input

    两行两个字符串,分别代表S和T

    Output

    第一行一个正整数k,表示T在S中出现了几次

    接下来k行正整数,分别代表T每次在S中出现的开始位置。按照从小到大的顺序输出,S下标从0开始。

    Sample Input

    bbabaababaaaaabaaaaaaaabaaabbbabaaabbabaabbbbabbbbbbabbaabbbababababbbbbbaaabaaabbbbbaabbbaabbbbabab
    a?aba?abba

    Sample Output

    0

    HINT

    S 长度不超过 10^5, T 长度不会超过 S。 S 中只包含小写字母, T中只包含小写字母和“?”

    Solution

    将字符串转化
    对于每个位置,如果 (s_i) 为正常字母,那么赋值为 (s_i-96) ,如果是问号,那么赋值为 (0)
    S赋值出的数组是 (x) ,T赋值出的数组是 (y)
    令S中一个位置的权值为 (f(i)=sum_{j=0}^{i}(x_{i-j}-y_{len_T-j})^2y_{i-j})
    那么如果在S中以 (i) 位置结尾的子串能够和T匹配,(f(i)=0)
    这还是不好算,但是这形式就是在提示我们要用套路了
    (y) 数组反过来, (f(i)=sum_{j=0}^{i}(x_{i-j}-y_{j})^2y_{j})
    拆开, (f(i)=sum_{j=0}^ix_{i-j}^2y_j-2x_{i-j}y_j^2+y_j^3)
    两个卷积加上一个三次方权值和
    FFT求解就好了

    #include<bits/stdc++.h>
    #define ui unsigned int
    #define ll long long
    #define db double
    #define ld long double
    #define ull unsigned long long
    const db Pi=acos(-1.0);
    const int MAXN=1<<19;
    int n1,n2,n,m,rev[MAXN],sum,f[MAXN],cnt,nt,ans[MAXN];
    char s1[MAXN],s2[MAXN];
    struct Complex{
    	db real,imag;
    	inline Complex operator + (const Complex &A) const {
    		return (Complex){real+A.real,imag+A.imag};
    	};
    	inline Complex operator - (const Complex &A) const {
    		return (Complex){real-A.real,imag-A.imag};
    	};
    	inline Complex operator * (const Complex &A) const {
    		return (Complex){real*A.real-imag*A.imag,imag*A.real+real*A.imag};
    	};
    };
    Complex x[MAXN],y[MAXN],xf[MAXN],yf[MAXN];
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char ch='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(ch!='')putchar(ch);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline void FFT(Complex *A,int tp)
    {
    	for(register int i=0;i<n;++i)
    		if(i<rev[i])std::swap(A[i],A[rev[i]]);
    	for(register int l=2;l<=n;l<<=1)
    	{
    		Complex wn=(Complex){cos(2*Pi/l),sin(tp*2*Pi/l)};
    		for(register int i=0;i<n;i+=l)
    		{
    			Complex w=(Complex){1,0};
    			for(register int j=0;j<(l>>1);++j)
    			{
    				Complex A1=A[i+j],A2=w*A[i+j+(l>>1)];
    				A[i+j]=A1+A2;A[i+j+(l>>1)]=A1-A2;
    				w=w*wn;
    			}
    		}
    	}
    }
    int main()
    {
    	scanf("%s",s1);scanf("%s",s2);
    	n1=strlen(s1);n2=strlen(s2);
    	m=n1+n2-1;
    	for(n=1;n<m;n<<=1)cnt++;
    	for(register int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(cnt-1));
    	for(register int i=0;i<n1;++i)x[i].real=(s1[i]-'a'+1)*2,xf[i].real=x[i].real*x[i].real/4.0;
    	for(register int i=0;i<n2;++i)y[n2-i-1].real=(s2[i]=='?'?0:s2[i]-'a'+1);
    	for(register int i=0;i<n2;++i)sum+=y[i].real*y[i].real*y[i].real,yf[i].real=y[i].real*y[i].real;
    	FFT(x,1);FFT(y,1);FFT(xf,1);FFT(yf,1);
    	for(register int i=0;i<n;++i)x[i]=xf[i]*y[i]-x[i]*yf[i];
    	FFT(x,-1);
    	for(register int i=0;i<n1-n2+1;++i)
    		if((int)(x[n2+i-1].real/n+sum+0.5)==0)ans[++nt]=i;
    	write(nt,'
    ');
    	for(register int i=1;i<=nt;++i)write(ans[i],'
    ');
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    Intel 10nm全系曝光!巨头也跑不动了
    国产智能手机占据半壁江山却依旧难掩三大尴尬事实
    顺势而为,HTML发展与UI组件设计进化
    怎么让引导不再是无用小透明?
    C++BUILDER的文件操作
    C++ Builder获取系统文件的路径
    C++Builder 常用String
    C++ 判断是否为邮箱格式
    AnsiString, String, char,char
    BCB如何编写,调用动态链接库DLL
  • 原文地址:https://www.cnblogs.com/hongyj/p/9179642.html
Copyright © 2011-2022 走看看