4503: 两个串

 

4503: 两个串

https://www.lydsy.com/JudgeOnline/problem.php?id=4503

题意:

  求第二个串在第一个中出现了几次,用通配符。求出每个串的起始位置。

分析:

  bitset。

  一共有26个字母,求出每个字母在第一个串中出现的位置。扫一遍第二个串,ans = p[[1]] & (p[T[2]]>>1) & (p[T[3]>>3]) & ... & p[T[n]>>n]。很好理解,就是每个字符所有出现的位置往右移,如果匹配,那么这一位and后,为1。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cctype>
#include<bitset>
using namespace std;

const int N = 200001;

bitset<N> p[26], ans;
char s[N], t[N];

int main() { 
    scanf("%s", s); int l1 = strlen(s);
    scanf("%s", t); int l2 = strlen(t);
    for (int j=0; j<26; ++j) 
        for (int i=0; i<l1; ++i) 
            if (s[i] - 'a' == j) p[j].set(i);
    for (int i=0; i<=l1-l2; ++i) ans.set(i);
    for (int i=0; i<l2; ++i) {
        if (t[i] == '?') continue;
        ans &= (p[t[i] - 'a'] >> i);
    }
    cout << ans.count() << "\n";
    for (int i=0; i<l1; ++i) 
        if (ans[i]) printf("%d\n", i);
    return 0;
}
View Code 

 

FFT的做法:

如果T出现在S中,那么有$\sum\limits_{i=0}^{m-1} (S_i-T_i)^2=0$

如果出现通配符,如果T出现在S中,那么设T[i]=0,那么有$\sum\limits_{i=0}^{m-1} (S_i-T_i)^2 \times T[i]=0$

然后将式子拆开$\sum\limits_{i=0}^{m-1} S_i^2T_i-2S_iT_i^2+T_i^3=0$

把T翻转,然后FFT即可。

当然,这只是对应到第一个位置的情况,其他的情况类似只需要将卷积后的指数改一下即可。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 270005;
const double Pi = acos(-1.0), eps = 1e-10;
struct Com{
    double x, y;
    Com(double _x = 0, double _y = 0) { x = _x, y = _y; }
}a[N], b[N], a2[N], b2[N], C[N]; double b3;
Com operator + (const Com &A,const Com &B) { return Com(A.x + B.x, A.y + B.y); }
Com operator - (const Com &A,const Com &B) { return Com(A.x - B.x, A.y - B.y); }
Com operator * (const Com &A,const Com &B) { return Com(A.x * B.x - A.y * B.y, A.x * B.y + A.y * B.x); }

char s[N], t[N];
int rev[N], S[N], T[N], c[N];
vector<int> ans;

void FFT(Com *a,int len,int ty) {
    for (int i = 0; i < len; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]);
    Com w1, w, u, t;
    for (int m = 2; m <= len; m <<= 1) {
        w1 = Com(cos(2 * Pi / m), ty * sin(2 * Pi / m));
        for (int i = 0; i < len; i += m) {
            w = Com(1, 0);
            for (int k = 0; k < (m >> 1); ++k) {
                u = a[i + k], t = w * a[i + k + (m >> 1)];
                a[i + k] = u + t;
                a[i + k + (m >> 1)] = u - t;
                w = w * w1;
            }
        }
    }
}
int main() {
    scanf("%s%s", s, t);
    int n = strlen(s), m = strlen(t), len = 1, lg = 0;
    while (len < n + m) len <<= 1, lg ++;
    for (int i = 0; i < len; ++i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));
    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] = Com(2 * S[i], 0), a2[i] = Com(S[i] * S[i], 0);
    reverse(T, T + m);
    for (int i = 0; i < m; ++i) 
        b[i] = Com(T[i], 0), b2[i] = Com(T[i] * T[i], 0), b3 += T[i] * T[i] * T[i];
    FFT(a2, len, 1); 
    FFT(b, len, 1);    
    FFT(a, len, 1);
    FFT(b2, len, 1);
    for (int i = 0; i < len; ++i) C[i] = a2[i] * b[i] - a[i] * b2[i];
    FFT(C, len, -1);
    for (int i = 0; i < len; ++i) C[i].x = C[i].x / (double)len;
    for (int i = 0; i < len; ++i) c[i] = floor(C[i].x + b3 + 0.5);
    for (int i = m - 1; i < n; ++i) if (c[i] == 0) ans.push_back(i - m + 1);
    printf("%d\n", (int)ans.size());
    for (int i = 0; i < (int)ans.size(); ++i) printf("%d\n", ans[i]);
    return 0;
}
View Code

 

posted @ 2018-10-09 19:38  MJT12044  阅读(225)  评论(0编辑  收藏  举报