bzoj 4259 殘缺的字符串

題目:bzoj4259 殘缺的字符串
洛谷無需權限

今天剛學的fft,於是專門找的這類題;
由於知道算法是什麼,就奔着fft上想了;
比較容易就能得出,如果將模板串翻轉位置之後,不足的位置補零再與要匹配的串做fft,那麼得出的多項式中F[ i ]是所有下標之和爲i的兩個字符的乘積,而由於模板串後邊的位置被補零,所以能夠找到n-m個F[i]表示所有匹配情況;
接下來考慮怎麼判斷每個情況是否合法,將模板串中26個字母都設爲一個數,再將匹配串中所有字母設爲倒數,如果有“*”號那麼設爲0,那麼得出的每個表示匹配情況的值如果是個整數,就是合法的,如果不是就不合法;
當然這樣有可能有精度問題,所以得給每個字符一開始的值加一個數,似乎加個1000左右的數就可以,加個100以內的可能會被卡;
至於判斷是否是整數時,實測1e-6也是可以過;
總之這個做法比較玄學,但唯一的好處是隻需要做一次fft,跑得比較快

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define random(a,b) (a+rand()%(b-a+1))
#define pi 3.141592653589793238460643383279
const int maxn=1048577;
int n,m;
int nn=1,tk=0;
int a[maxn],b[maxn],c[maxn];
double abs(double x)
{
    if(x<0)return -x;
    return x;
} 
struct com
{
    double r,i;
    com(){
        r=i=0.0;
    }
    com(double x,double y){
        r=x,i=y;    
    } 
    com operator +(const com &o)const{
        return com(r+o.r,i+o.i);
    }
    com operator -(const com &o)const{
        return com(r-o.r,i-o.i);
    }
    com operator *(const com &o)const{
        return com(r*o.r-i*o.i,r*o.i+i*o.r);
    }
    com operator /(const double &o)const{
        return com(r/o,i/o);
    }
}c1[maxn],c2[maxn], omega[maxn];
void read(register int *t,int len)
{
    char s;
    for(register int i=0;i<len;i++)
    {
        s=getchar();
        while(!isdigit(s))s=getchar();
        t[i]=s-'0';
    }
}
void swap(com &x,com &y)
{
    com z=x;
    x=y;
    y=z;
}
void FFT(com *p)
{
    for(register int i=0,j=0; i<nn; i++)
    {
        if(i>j)swap(p[i],p[j]);
        for(register int l=nn>>1; (j^=l)<l; l>>=1);
    }
    for(register int l=2;l<=nn;l<<=1)
    {
        int mid=l/2;
        for(com *t=p;t!=p+nn;t+=l)
        for(register int i=0;i<mid;i++)
        {
            com tp=omega[nn/l*i] * t[i+mid];
            t[i+mid]=t[i]-tp;
            t[i]=t[i]+ tp;
        }
    }
}
com f[maxn],g[maxn];
int suma=0,sumb=0;
char sb[maxn];
int ans[maxn];
int anstot=0;
int main()
{
    scanf("%d%d",&m,&n);
    scanf("%s",sb);
    for(int i=0;i<m;i++)
    {
        if(sb[i]=='*')f[m-1-i].r=0.0,sumb++;
        else f[m-1-i].r=(double)(sb[i]-'a'+1000);
    }
    scanf("%s",sb);
    for(int i=0;i<n;i++)
    {
        if(sb[i]=='*')g[i].r=0.0;
        else g[i].r=1.0/(double)(sb[i]-'a'+1000);   
    } 
    while(nn<m+n-1)nn<<=1;
    for(register int i=0;i<nn;i++)omega[i]=com(std::cos(2.0*pi/(double)nn*(double)(i)),std::sin(2.0*pi/(double)nn*(double)i));
    FFT(f);
    FFT(g);
    for(register int i=0;i<nn;i++)
    {
        omega[i].i*=-1;
        f[i]=f[i]*g[i];
    }
    FFT(f);
    for(register int i=0;i<nn;i++)
        f[i].r/=(double)nn;
    for(int i=m-1;i<n;i++)
    {
        int tmp=(int)(f[i].r+0.5);//四捨五入
        if(abs(f[i].r-(double)tmp)<=1e-6)ans[++anstot]=i-m+2;
    }
    printf("%d\n",anstot);
    for(int i=1;i<=anstot;i++)printf("%d ",ans[i]); 
        return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章