bzoj 4259 4259: 残缺的字符串【FFT】

和bzoj 4503 https://www.cnblogs.com/lokiii/p/10032311.html 差不多,就是再乘上一个原串字符

有点卡常,先在点值下算最后一起IDFT

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1100005;
int n,m,bt,lm,re[N],tot;
long long x[N],y[N];
double sm;
char s[N],t[N];
struct cd
{
    double a,b;
    cd(double A=0,double B=0)
    {
        a=A,b=B;
    }
    cd operator + (const cd &x) const
    {
        return cd(a+x.a,b+x.b);
    }
    cd operator - (const cd &x) const
    {
        return cd(a-x.a,b-x.b);
    }
    cd operator * (const cd &x) const
    {
        return cd(a*x.a-b*x.b,a*x.b+b*x.a);
    }
}a[N],b[N],c[N];
void dft(cd a[],int f)
{
    for(int i=0;i<lm;i++)
        if(i<re[i])
            swap(a[i],a[re[i]]);
    for(int i=1;i<lm;i<<=1)
    {
        cd wi=cd(cos(M_PI/i),f*sin(M_PI/i));
        for(int k=0;k<lm;k+=(i<<1))
        {
            cd w=cd(1,0),x,y;
            for(int j=0;j<i;j++)
            {
                x=a[j+k],y=w*a[i+j+k];
                a[j+k]=x+y,a[i+j+k]=x-y;
                w=w*wi;
            }
        }
    }
    if(f==-1)
        for(int i=0;i<lm;i++)
            a[i].a/=lm;
}
int main()
{
    scanf("%d%d%s%s",&n,&m,t,s);
    for(int i=0,j=n-1;i<j;i++,j--)
        swap(t[i],t[j]);
    for(int i=0;i<n;i++)
        x[i]=(t[i]==‘*‘)?0:t[i]-‘a‘+1,a[i].a=x[i]*x[i]*x[i];
    for(int i=0;i<m;i++)
        y[i]=(s[i]==‘*‘)?0:s[i]-‘a‘+1,b[i].a=y[i];
    for(bt=0;(1<<bt)<=n+m;bt++);
    lm=1<<bt;
    for(int i=0;i<lm;i++)
        re[i]=(re[i>>1]>>1)|((i&1)<<(bt-1));
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]+a[i]*b[i];
    for(int i=0;i<lm;i++)
        a[i]=cd(x[i],0),b[i]=cd(y[i]*y[i]*y[i],0);
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]+a[i]*b[i];
    for(int i=0;i<lm;i++)
        a[i]=cd(x[i]*x[i],0),b[i]=cd(y[i]*y[i],0);
    dft(a,1),dft(b,1);
    for(int i=0;i<lm;i++)
        c[i]=c[i]-a[i]*b[i]*cd(2,0);
    dft(c,-1);
    for(int i=n-1;i<m;i++)
        if((int)(c[i].a+0.5)==0)
            tot++;
    printf("%d\n",tot);
    for(int i=n-1;i<m;i++)
        if((int)(c[i].a+0.5)==0)
            printf("%d ",i-n+2);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/10036135.html

时间: 2024-07-31 12:24:47

bzoj 4259 4259: 残缺的字符串【FFT】的相关文章

BZOJ 4259 残缺的字符串 ——FFT

[题目分析] 同bzoj4503. 只是精度比较卡,需要试一试才能行O(∩_∩)O 用过long double,也加过0.4.最后发现判断的时候改成0.4就可以了 [代码] #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1200005 #

@bzoj - [email&#160;protected] 残缺的字符串

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n.可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺. 你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这

P4173 残缺的字符串 fft

题意:给你两个字符串,问你第一个在第二个中出现过多少次,并输出位置,匹配时是模糊匹配*可和任意一个字符匹配 题解:fft加速字符串匹配; 假设上面的串是s,s长度为m,下面的串是p,p长度为n,先考虑没有*的情况那么\(\sum_{j=1}^m(s_{i+j}-p_j)^2=0\)就表示能够从i开始匹配,现在考虑有*的情况,我们只需要让有*的和任意字符匹配即可,那么把公式变成\(\sum_{j=1}^m(s_{i+j}-p_j)^2*s_{i+j}*p_j)=0\),但是fft正向匹配太慢了,我

luogu P4173 残缺的字符串 FFT

温馨提示:倘若下角标看不清的话您可以尝试放大. 倘若没有通配符的话可以用KMP搞一搞. 听巨佬说通配符可以用FFT搞一搞. 我们先考虑一下没有通配符的怎么搞.我们设a=1,b=2,...,然后我们构造一个这样的函数\(\displaystyle P_x=\sum_{i=0}^{m-1}(A_i-B_{x-m+1+i})^2\),但且仅当A和B在x的位置上匹配完成的时候$P_x $为0.至于为什么是平方,主要是为了防止正数和负数相互抵消. 至于通配符,我们设它为0,我们尝试重新构造一下\(\dis

Luogu P4173 残缺的字符串

P4173 残缺的字符串 FFT在字符串匹配中的应用. 能解决大概这种问题: 给定长度为\(m\)的A串,长度为\(n\)的B串.问A串在B串中的匹配数 我们设一个函数(下标从\(0\)开始) \(C(x,y) =A(x)- B(y)\),若为0,表示B串中以第\(y\)个字符结尾的字符可以与A串中以\(x\)节为结尾的字符可以匹配 \(P(x) = \sum_{i = 0}^{m - 1}C(i,x - m + i + 1)\) 但是很遗憾当\(P(x)\),等于零时,只能够说明上述子串的字符

BZOJ[3527],[ZJOI2014]力(FFT)

BZOJ[3527],[ZJOI2014]力(FFT) 题意: 给出\(n\)个数\(q_i\),给出\(Fj\)的定义如下: \(F_j=\sum \limits _ {i < j} \frac{q_iq_j}{(i-j)^2}-\sum \limits _{i >j} \frac{q_iq_j}{(i-j)^2}.\) 令\(E_i=F_i/q_i\),求\(E_i\). 题解: 一开始没发现求\(E_i\)... 其实题目还更容易想了... \(E_i=\sum\limits _{j&l

【BZOJ】4259: 残缺的字符串

[题意]给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次.字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符.n<=3*10^5. [算法]FFT [题解]假设模板串的数组A用0~26代表所有字符,0为通配符,匹配串的数组B同理,那么用表示差异的经典套路: $$C_n=\sum_{i=0}^{m-1}(A_{n+i}-B_i)^2*A_{n+i}*B_i$$ 那么可以看出$C_n=0$当且仅当$S_A[n,n+m-1]=S_B[0,m-1]$

bzoj 4259: 残缺的字符串

这题好神啊,居然是fft,表示一直在往数据结构上想. 把'*'当成0,那么两个串可以匹配当且仅当$$\sum (a[i]-b[i])^2\times a[i]\times b[i]==0$$ 我们可以把平方拆开,然后就变成了几个乘积相加的形式,那就大力翻转一个串然后跑FFT. 因为最开始MLE了所以复制粘贴了好多东西. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<al

4259. 残缺的字符串

传送门 用 $FFT$ 搞字符串匹配,神仙操作.... 对于两个字符串 $A,B$,定义 $dis(A,B)=\sum_i(A_i-B_i)^2$ 显然当且仅当 $A=B$ 时,$dis(A,B)=0$ 这一题还有要求,'*' 为通配符,所以这题的 $dis(A,B)=\sum_i((A_i-B_i)^2[A_i!='*'][B_i!='*'])$ 发现这时如果设 '*' 为 $0$,则 $dis(A,B)=\sum_i((A_i-B_i)^2A_iB_i)$ 对于此题,设 $A$ 串为模板串,