zoukankan      html  css  js  c++  java
  • BZOJ 4503: 两个串 [FFT]

    4503: 两个串

    题意:兔子们在玩两个串的游戏。给定两个只含小写字母的字符串S和T,兔子们想知道T在S中出现了几次,
    分别在哪些位置出现。注意T中可能有“?”字符,这个字符可以匹配任何字符。


    为什么智障游戏总要让兔子来玩

    受到上题影响,直接每个字符算一遍最后加上?的个数,26倍常数完美TLE
    上一题是因为母串的每个位置可以匹配几种字符我们才那么做,对于只有相等匹配和万能匹配的问题不用那样做


    我们可以直接构造这样一个卷积,
    (a_i=s_i)
    (b_i=t_i, t_i eq ?)
    (b_i=0, t_i=?)

    [c_i = sum_{i=0}^{m-1}(a_{j+i}-b_i)^2b_i=D_{m-1+j} ]

    这样的话能匹配当且仅当相等或者模式串为?
    化简后反转模式串就是两个卷积+一个函数卷1加起来的形式
    注意:最后一个是(b_i^3),如果强行放到fft里计算必须要卷上一个常数函数(1)才行,否则直接fft算完后加上他就可以了,他对每一项是相等的


    一开始反转模式串的时候直接用t[m-1+i]了wa了好久...

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=(1<<18)+5;
    const double PI=acos(-1);
    inline int read(){
    	char c=getchar();int x=0,f=1;
    	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    	return x*f;
    }
     
    struct meow{
    	double x, y;
    	meow(double a=0, double b=0):x(a), y(b){}
    };
    meow operator +(meow a, meow b) {return meow(a.x+b.x, a.y+b.y);}
    meow operator -(meow a, meow b) {return meow(a.x-b.x, a.y-b.y);}
    meow operator *(meow a, meow b) {return meow(a.x*b.x-a.y*b.y, a.x*b.y+a.y*b.x);}
    meow conj(meow a) {return meow(a.x, -a.y);}
    typedef meow cd;
     
    namespace FFT{
    	int n, rev[N];
    	void ini(int lim) {
    		n=1; int k=0;
    		while(n<lim) n<<=1, k++;
    		for(int i=0; i<n; i++) rev[i] = (rev[i>>1]>>1) | ((i&1)<<(k-1));
    	}
    	void dft(cd *a, int flag) {
    		for(int i=0; i<n; i++) if(i<rev[i]) swap(a[i], a[rev[i]]);
    		for(int l=2; l<=n; l<<=1) {
    			int m=l>>1; 
    			cd wn = meow(cos(2*PI/l), flag*sin(2*PI/l));
    			for(cd *p=a; p!=a+n; p+=l) {
    				cd w(1, 0);
    				for(int k=0; k<m; k++) {
    					cd t = w*p[k+m];
    					p[k+m] = p[k] - t;
    					p[k] = p[k] + t;
    					w=w*wn;
    				}
    			}
    		}
    		if(flag==-1) for(int i=0; i<n; i++) a[i].x/=n;
    	}
    }using FFT::dft; using FFT::ini;
     
    int n, m, lim;
    cd a[N], b[N], a2[N], b2[N], c[N]; double b3;
    char s[N], t[N];
    int ans, li[N];
    int main() {
    	freopen("pn","r",stdin);
    	scanf("%s%s",s,t);
    	n=strlen(s); m=strlen(t); lim=n+m-1; ini(lim);
    	for(int i=0; i<n; i++) s[i]=s[i]-'a'+1;
    	for(int i=0; i<m; i++) t[i]= t[i]=='?' ? 0 : t[i]-'a'+1;
     
    	for(int i=0; i<n; i++) a[i].x = 2*s[i], a2[i].x = s[i]*s[i];
    	for(int i=0; i<m; i++) {
    		int p=m-1-i;
    		b[p].x = t[i], b2[p].x = t[i]*t[i], b3 += t[i]*t[i]*t[i];
    	}
    	 
    	dft(a, 1); dft(a2, 1); dft(b, 1); dft(b2, 1);
    	for(int i=0; i<FFT::n; i++) c[i] = a2[i]*b[i] - a[i]*b2[i];
    	dft(c, -1);
    	for(int i=0; i<=n-m; i++) if(floor(c[m-1+i].x+b3+0.5)==0) li[++ans]=i;
    	printf("%d
    ",ans);
    	for(int i=1; i<=ans; i++) printf("%d
    ",li[i]);
    }
    
  • 相关阅读:
    大众CAN TP2.0协议说明
    统一诊断服务 (Unified diagnostic services , UDS) (七)
    统一诊断服务 (Unified diagnostic services , UDS) (六)
    统一诊断服务 (Unified diagnostic services , UDS) (五)
    统一诊断服务 (Unified diagnostic services , UDS) (四)
    统一诊断服务 (Unified diagnostic services , UDS) (三)
    asp.net 网页拉伸 到300%不变形方法一
    C# WinForm 禁止最大化、最小化、双击标题栏、双击图标等操作记录
    VS系列软件中debug和release编译环境有什么区别
    软件设计开发思想总结
  • 原文地址:https://www.cnblogs.com/candy99/p/6648738.html
Copyright © 2011-2022 走看看