luoguP4173 残缺的字符串 FFT

luoguP4173 残缺的字符串 FFT

链接

luogu

思路

和昨天做的题几乎一样。
匹配等价于(其实我更喜欢fft从0开始)
\(\sum\limits_{i=0}^{m-1}(S[i+j]-T[i])^2*T[i]*S[i]=0\)
展开得到
\(\sum\limits_{i=0}^{m-1}S_{i+j}^3T_{i}+\sum\limits\S_{i+j}T_{i}^3-2\sum\limits\S_{i+j}^2T_{i}^2=0\)
反转T串串
\(\sum\limits_{i=0}^{m-1}S_{i+j}^3T_{m-1-i}+\sum\limits\S_{i+j}T_{m-1-i}^3-2\sum\limits\S_{i+j}^2T_{m-1-i}^2=0\)
然后三次卷积就行了。
写完看了看别的代码,感觉自己的代码太蠢了,多fft了好几次。

错误

我居然同样的错误犯了好几遍。
昨天也是wrong在最后从0到n-m判断,这次又是。
而且我还想了好久。

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1200000+7;
const double Pi=acos(-1),eps=1e-9;
int limit=1,p,r[N<<1];
int fff(int x) {return x*x*x;}
int ff(int x) {return x*x;}
struct Complex {
    double x,y;
    Complex(double xx=0,double yy=0) {x=xx,y=yy;}
}a[N<<1],b[N<<1],tot[N<<1];
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.y*b.x+b.y*a.x);}
void fft(Complex *a,int type) {
    for(int i=0;i<limit;++i)
        if(i<r[i]) swap(a[r[i]],a[i]);
    for(int mid=1;mid<limit;mid<<=1) {
        Complex Wn(cos(Pi/mid),type*sin(Pi/mid));
        for(int i=0;i<limit;i+=mid<<1) {
            Complex w(1,0);
            for(int j=0;j<mid;++j,w=w*Wn) {
                Complex x=a[i+j],y=w*a[i+j+mid];
                a[i+j]=x+y;
                a[i+j+mid]=x-y;
            }
        }
    }
    if(type==-1) for(int i=0;i<limit;++i) a[i].x/=limit;
}
int n,m,s[N],t[N];
char S[N],T[N];
int main() {
    scanf("%d%d%s%s",&m,&n,T,S);
    for(int i=0;i<n;++i) s[i]=S[i]=='*'?0:S[i]-'a'+1;
    for(int i=0;i<m;++i) t[m-i-1]=T[i]=='*'?0:T[i]-'a'+1;
    while(limit<n+m) limit<<=1,p++;
    for(int i=0;i<limit;++i)
        r[i]=(r[i>>1]>>1)|((i&1)<<(p-1));
    
    for(int i=0;i<limit;++i) a[i]=Complex(s[i],0),b[i]=Complex(fff(t[i]),0);
    fft(a,1),fft(b,1);
    for(int i=0;i<limit;++i) tot[i]=tot[i]+a[i]*b[i];
    
    
    for(int i=0;i<limit;++i) a[i]=Complex(fff(s[i]),0),b[i]=Complex(t[i],0);
    fft(a,1),fft(b,1);
    for(int i=0;i<limit;++i) tot[i]=tot[i]+a[i]*b[i];

    
    for(int i=0;i<limit;++i) a[i]=Complex(ff(s[i]),0),b[i]=Complex(ff(t[i]),0);
    fft(a,1),fft(b,1);
    for(int i=0;i<limit;++i) tot[i]=tot[i]-a[i]*b[i]*Complex(2,0);

    fft(tot,-1);
    
    int ans=0;
    for(int i=0;i<n-m+1;++i) if(fabs(round(tot[m+i-1].x))<eps) ans++;
    printf("%d\n",ans);
    for(int i=0;i<n-m+1;++i) if(fabs(round(tot[m+i-1].x))<eps) printf("%d ",i+1);
    return 0;
}

转载于:https://www.cnblogs.com/dsrdsr/p/11219437.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值