弱省互測#2 t3

題意

給出\(n\)個01字節和\(m\)個01字節,要求用後者去匹配前者,兩個串能匹配當且僅當除了每一個字節末位不一樣,其餘位都要相同。問匹配後者至少有多少個末位不一樣。(\(1 \le m \le n \le 2.5 \times 10^5\)c++

分析

首先咱們能夠用kmp計算出能匹配的位置,而後單獨考慮末位不一樣的狀況。spa

題解

咱們將末尾的位提取出來,則考慮\(n\)\(01\)位和\(m\)\(01\)位。對於模板串的\(01\)位,咱們須要計算以這個位置結束與匹配串位相同的數目,發現其實咱們將匹配串反轉,而後就是卷積!因而咱們就能夠用fft作了。code

#include <bits/stdc++.h>
using namespace std;
const double pi=acos(-1);
const int N=2.5e5+10, nS=N*8, Lim=600006;
int lenn, lenm, lena, lenb, got[Lim], rev[Lim];
char s1[nS], s2[nS], sa[nS], sb[nS];
vector<int> pos;
void getkmp() {
    static int p[nS];
    memset(p, -1, sizeof(int)*lena);
    int j=-1;
    for(int i=1; i<lena; ++i) {
        while(j!=-1 && sa[j+1]!=sa[i]) j=p[j];
        if(sa[j+1]==sa[i]) ++j;
        p[i]=j;
    }
    j=-1;
    for(int i=0; i<lena; ++i) {
        while(j!=-1 && sb[j+1]!=sa[i]) j=p[j];
        if(sb[j+1]==sa[i]) ++j;
        if(j==lenb-1) {
            int t=i-j;
            if(t%7==0) {
                pos.push_back(t/7);
            }
        }
    }
}
struct icp {
    double r, i;
    icp(double _r=0, double _i=0) : r(_r), i(_i) { }
};
icp operator + (const icp &a, const icp &b) { return icp(a.r+b.r, a.i+b.i); }
icp operator - (const icp &a, const icp &b) { return icp(a.r-b.r, a.i-b.i); }
icp operator * (const icp &a, const icp &b) { return icp(a.r*b.r-a.i*b.i, a.r*b.i+a.i*b.r); }
int getlen(int n) {
    int len=1, bl=-1;
    for(; len<n; len<<=1, ++bl);
    for(int i=0; i<len; ++i) {
        rev[i]=(rev[i>>1]>>1)|((i&1)<<bl);
    }
    return len;
}
void fft(icp *a, int n, int flag) {
    for(int i=0; i<n; ++i) {
        if(rev[i]<i) {
            swap(a[rev[i]], a[i]);
        }
    }
    for(int m=2; m<=n; m<<=1) {
        icp wn(cos(pi*2/m), sin(pi*2/m)*flag);
        for(int i=0, mid=m>>1; i<n; i+=m) {
            icp w(1);
            for(int j=0; j<mid; ++j) {
                icp u=a[i+j], v=a[i+j+mid]*w;
                a[i+j]=u+v;
                a[i+j+mid]=u-v;
                w=w*wn;
            }
        }
    }
    if(flag==-1) {
        for(int i=0; i<n; ++i) {
            a[i].r/=n;
        }
    }
}
void dofft(char *A, char *B, int *C, int n, int m) {
#define CLR(a) for(int i=0; i<len; ++i) a[i].r=a[i].i=0;
    static icp a[Lim], b[Lim], c[Lim];
    int len=getlen(n+m-1);
    CLR(a);
    CLR(b);
    CLR(c);
    for(int i=0; i<n; ++i)
        a[i].r=A[i]-'0';
    for(int i=0; i<m; ++i)
        b[i].r=B[i]-'0';
    fft(a, len, 1);
    fft(b, len, 1);
    for(int i=0; i<len; ++i)
        c[i]=a[i]*b[i];
    fft(c, len, -1);
    for(int i=0; i<len; ++i)
        C[i]+=c[i].r+0.5;
}
void getfft() {
    lena=lenb=0;
    for(int i=7; i<lenn; i+=8)
        sa[lena++]=s1[i];
    for(int i=lenm-1; i>=0; i-=8)
        sb[lenb++]=s2[i];
    dofft(sa, sb, got, lena, lenb);
    for(int i=0; i<lena; ++i)
        sa[i]=sa[i]=='0'?'1':'0';
    for(int i=0; i<lenb; ++i)
        sb[i]=sb[i]=='0'?'1':'0';
    dofft(sa, sb, got, lena, lenb);
}
int main() {
    int n, m;
    scanf("%d%d", &n, &m);
    lenn=n*8, lenm=m*8;
    char *it;
    it=s1;
    for(int i=0; i<n; ++i) {
        scanf("%s", it);
        for(; *it; ++it) {
            if(*(it+1)) {
                sa[lena++]=*it;
            }
        }
    }
    it=s2;
    for(int i=0; i<m; ++i) {
        scanf("%s", it);
        for(; *it; ++it) {
            if(*(it+1)) {
                sb[lenb++]=*it;
            }
        }
    }
    getkmp();
    getfft();
    if(!pos.size()) {
        puts("No");
        return 0;
    }
    int ans1=n, ans2=~0u>>1;
    for(int i=0, len=pos.size(); i<len; ++i) {
        int p=pos[i], t=(m-got[p+m-1]);
        if(ans2==t) {
            ans1=min(p, ans1);
        }
        else if(ans2>t) {
            ans2=t;
            ans1=p;
        }
    }
    printf("Yes\n%d %d\n", ans2, ans1+1);
    return 0;
}
相關文章
相關標籤/搜索