zoukankan      html  css  js  c++  java
  • CF-528D Fuzzy Search(FFT字符串匹配)

    Fuzzy Search

    题意:

    给定一个模式串和目标串按下图方式匹配,错开位置不多于k
    此处输入图片的描述

    解题思路:

    总共只有(A C G T)四个字符,那么我们可以按照各个字符进行匹配,比如按照(A)进行匹配时,当(k=1)时,我们将目标串
    (ACAT)化作
    (1~0~1~0)
    模式串
    (AGCAATTCAT)化作
    (1~1~1~1~1~1~0~1~1~1)
    同样是反置目标串
    可以得到以x为匹配终点的位置的匹配函数(p(X)=sum_{i+j=x}A(i)B(j))
    如此进行4次FFT,最后如果目标位置贡献等于目标串长度,则说明匹配成功

    #include <bits/stdc++.h>
    using namespace std;
    /*    freopen("k.in", "r", stdin);
        freopen("k.out", "w", stdout); */
    //clock_t c1 = clock();
    //std::cerr << "Time:" << clock() - c1 <<"ms" << std::endl;
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    #define de(a) cout << #a << " = " << a << endl
    #define rep(i, a, n) for (int i = a; i <= n; i++)
    #define per(i, a, n) for (int i = n; i >= a; i--)
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> PII;
    typedef pair<double, double> PDD;
    typedef vector<int, int> VII;
    #define inf 0x3f3f3f3f
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const ll MAXN = 1e6 + 7;
    const ll MAXM = 1e6 + 7;
    const ll MOD = 998244353;
    const double eps = 1e-6;
    const double pi = acos(-1.0);
    template <class T>
    inline void in(T &x)
    {
        static char ch;
        static bool neg;
        for (ch = neg = 0; ch < '0' || '9' < ch; neg |= ch == '-', ch = getchar())
            ;
        for (x = 0; '0' <= ch && ch <= '9'; (x *= 10) += ch - '0', ch = getchar())
            ;
        x = neg ? -x : x;
    }
    
    struct Complex
    {
        double x, y;
        Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
    } a[MAXN], b[MAXN], c[MAXN], ans[MAXN];
    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.x * b.y + a.y * b.x); } //不懂的看复数的运算那部分
    int N, M;
    int l, r[MAXN];
    int limit = 1;
    void FFT(Complex *A, int type)
    {
        for (int i = 0; i < limit; i++)
            if (i < r[i])
                swap(A[i], A[r[i]]); //求出要迭代的序列
        for (int mid = 1; mid < limit; mid <<= 1)
        {                                                    //待合并区间的长度的一半
            Complex Wn(cos(pi / mid), type * sin(pi / mid)); //单位根
            for (int R = mid << 1, j = 0; j < limit; j += R)
            {                    //R是区间的长度,j表示前已经到哪个位置了
                Complex w(1, 0); //幂
                for (int k = 0; k < mid; k++, w = w * Wn)
                {                                                 //枚举左半部分
                    Complex x = A[j + k], y = w * A[j + mid + k]; //蝴蝶效应
                    A[j + k] = x + y;
                    A[j + mid + k] = x - y;
                }
            }
        }
        /*if (type == -1)
            for (int i = 0; i < limit; ++i)
                a[i].x /= limit;//我们推过的公式里面有一个1/n这一项*/
    }
    char s[MAXN], t[MAXN];
    void init(int N, int M)
    {
        while (limit <= N + M)
            limit <<= 1, l++;
        for (int i = 0; i < limit; i++)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
    }
    int change(char str)
    {
        if (str == 'A')
            return 1;
        else if (str == 'T')
            return 2;
        else if (str == 'G')
            return 3;
        else
            return 4;
    }
    int pre[MAXN], cnt;
    int main()
    {
        int n, m, k;
        scanf("%d%d%d %s %s", &n, &m, &k, s, t);
        reverse(t, t + m);
        init(n, m);
        for (int ca = 1; ca <= 4; ca++)
        {
            cnt = -1;
            memset(pre, 0, sizeof(pre));
            memset(a, 0, sizeof(a));
            memset(b, 0, sizeof(b));
            for (int i = 0; i < n; i++)
            {
                if (change(s[i]) == ca)
                    pre[++cnt] = i;
                a[i].x = change(s[i]) == ca ? 1 : 0, a[i].y = 0;
            }
            for (int i = 0; i < m; i++)
                b[i].x = change(t[i]) == ca ? 1 : 0, b[i].y = 0;
            int now = -1;
            for (int i = 0; i <= cnt; i++)
            {
                int L = max(pre[i] - k, 0);
                int R = min(pre[i] + k, n - 1);
                if (now > R)
                    continue;
                now = max(L, now);
                for (; now <= R; now++)
                    a[now].x = 1;
                now--;
            }
            FFT(a, 1);
            FFT(b, 1);
            for (int i = 0; i < limit; i++)
                a[i] = b[i] * a[i];
            FFT(a, -1);
            for (int i = 0; i < limit; i++)
                c[i] = c[i] + a[i];
        }
        int ans = 0;
        for (int i = m - 1; i < limit; i++)
            if (int(c[i].x / limit + 0.5) == m)
                ans++;
        printf("%d
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    2019-2020-1学期20192412《网络空间安全专业导论》第十二周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第十一周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第十周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第九周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第八周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第七周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第六周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第五周学习总结
    #2019-2020-1学期20192412《网络空间安全专业导论》第四周学习总结
    2019-2020-1学期20192412《网络空间安全专业导论》第三周学习总结
  • 原文地址:https://www.cnblogs.com/graytido/p/11789975.html
Copyright © 2011-2022 走看看