P3763 [TJOI2017]DNA 题解

写一个比大部分做法跑得快的哈希(最优解 rk3)。

枚举 $S_0$ 子串的开头,二分找失配位置,在失配位置后二分找下一个失配位置,以此类推。

如果第 $4$ 个失配位置在子串外,那么这个子串符合要求。

考虑字符集大小只有 $4$,$\text{base}$ 取 $5$ 即可。

直接自然溢出啥事没有。

#include <stdio.h>
#include <string.h>
int T, n, m, l, q;
char a[100050], b[100050];
unsigned p[100050], f[100050], g[100050];
int main()
{
    p[0] = 1;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%s%s", a + 1, b + 1);
        n = strlen(a + 1);
        m = strlen(b + 1);
        for (int k = m; l < k; ++l, p[l] = p[l - 1] * 5)
            ;
        for (int i = 1; i <= n; ++i)
        {
            f[i] = f[i - 1] * 5;
            switch (a[i])
            {
            case 'T':
                f[i] += 1;
                break;
            case 'C':
                f[i] += 2;
                break;
            case 'G':
                f[i] += 3;
                break;
            }
        }
        for (int i = 1; i <= m; ++i)
        {
            g[i] = g[i - 1] * 5;
            switch (b[i])
            {
            case 'T':
                g[i] += 1;
                break;
            case 'C':
                g[i] += 2;
                break;
            case 'G':
                g[i] += 3;
                break;
            }
        }
        q = 0;
        for (int i = 1; i + m - 1 <= n; ++i)
            for (int j = 0, x = 0, l, r = 0; j < 4; ++j)
            {
                l = 0;
                x += r + 1;
                r = m - x + 1;
                while (l <= r)
                {
                    int m = l + r >> 1;
                    unsigned u = p[m];
                    if (f[i + x + m - 2] - f[i + x - 2] * u == g[x + m - 1] - g[x - 1] * u)
                        l = m + 1;
                    else
                        r = m - 1;
                }
                if (r == m - x + 1)
                {
                    ++q;
                    break;
                }
            }
        printf("%d\n", q);
    }
    return 0;
}
posted @ 2022-12-11 17:43  Jijidawang  阅读(9)  评论(0编辑  收藏  举报  来源