• 省队集训 Day1 残缺的字符串


    【题目大意】

    双串带通配符匹配。

    $|S|, |T| leq 5 * 10^5$

    TL: 2s

    【题解】

    参考bzoj 4503

    可以设计如下函数 A[i] * B[i] * (A[i] - B[i])^2

    如果有通配符,A[i] = 0,否则,A[i] = s[i] - 'a' + 1;B同理。

    可以自行验证,这是一种很妙的设计。

    然后就是卷积的事情了。大概做9次DFT。

    可以用类似于MTT的技巧搞到4次,不会写。

    # include <math.h>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 5e5 + 10, N = 2e6 + 10;
    const int mod = 1e9+7;
    const ld pi = acos(-1.0);
    
    char s[M], t[M];
    int A[M], B[M], ns, nt;
    
    struct cp {
        ld x, y;
        cp() {}
        cp(ld x, ld y) : x(x), y(y) {}
        friend cp operator + (cp a, cp b) {
            return cp(a.x + b.x, a.y + b.y);
        }
        friend cp operator - (cp a, cp b) {
            return cp(a.x - b.x, a.y - b.y);
        }
        friend cp operator * (cp a, cp b) {
            return cp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
        }
    }a[N], b[N], ans[N];
    
    namespace FFT {
        int n, lst[N]; cp w[2][N];
        inline void set(int _n) {
            n = 1;
            while(n < _n) n <<= 1;
            for (int i=0; i<n; ++i) w[0][i] = cp(cos(pi * 2 / n * i), sin(pi * 2 / n * i)), w[1][i] = cp(w[0][i].x, -w[0][i].y);
            int len = 0;
            while((1<<len) < n) ++len;
            for (int i=0; i<n; ++i) {
                int t = 0;
                for (int j=0; j<len; ++j) if(i & (1<<j)) t |= (1<<(len-j-1));
                lst[i] = t;
            }
        }
        inline void DFT(cp *a, int op) {
            cp *o = w[op];
            for (int i=0; i<n; ++i) if(i < lst[i]) swap(a[i], a[lst[i]]);
            for (int len=2; len<=n; len<<=1) {
                int m = len>>1;
                for (cp *p=a; p!=a+n; p+=len) {
                    for (int k=0; k<m; ++k) {
                        cp t = o[n/len*k] * p[k+m];
                        p[k+m] = p[k] - t;
                        p[k] = p[k] + t;
                    }
                }
            }
            if(op) {
                for (int i=0; i<n; ++i) a[i].x /= (ld)n, a[i].y /= (ld)n;
            }
        }
    }
    
    # define L FFT::n
    
    int main() {
        scanf("%s%s", t, s); ns = strlen(s), nt = strlen(t);
        for (int i=0; i<ns; ++i) A[i] = (s[i] == '*' ? 0 : s[i] - 'a' + 1);
        for (int i=0; i<nt; ++i) B[i] = (t[i] == '*' ? 0 : t[i] - 'a' + 1);
        reverse(B, B+nt);
        // (A[i] - B[i])^2 * A[i] * B[i]  =  A[i]^3 * B[i] + A[i] * B[i]^3 - A[i]^2 * B[i]^2
        FFT :: set(max(ns, nt));
        for (int i=0; i<ns; ++i) a[i] = cp(A[i] * A[i] * A[i], 0);
        for (int i=ns; i<L; ++i) a[i] = cp(0, 0);
        for (int i=0; i<nt; ++i) b[i] = cp(B[i], 0);
        for (int i=nt; i<L; ++i) b[i] = cp(0, 0);
        FFT :: DFT(a, 0); FFT :: DFT(b, 0);
        for (int i=0; i<L; ++i) ans[i] = ans[i] + a[i] * b[i];
        for (int i=0; i<ns; ++i) a[i] = cp(A[i], 0);
        for (int i=ns; i<L; ++i) a[i] = cp(0, 0);
        for (int i=0; i<nt; ++i) b[i] = cp(B[i] * B[i] * B[i], 0);
        for (int i=nt; i<L; ++i) b[i] = cp(0, 0);
        FFT :: DFT(a, 0); FFT :: DFT(b, 0);
        for (int i=0; i<L; ++i) ans[i] = ans[i] + a[i] * b[i];
        for (int i=0; i<ns; ++i) a[i] = cp(A[i] * A[i] * 2, 0);
        for (int i=ns; i<L; ++i) a[i] = cp(0, 0);
        for (int i=0; i<nt; ++i) b[i] = cp(B[i] * B[i], 0);
        for (int i=nt; i<L; ++i) b[i] = cp(0, 0);
        FFT :: DFT(a, 0); FFT :: DFT(b, 0);
        for (int i=0; i<L; ++i) ans[i] = ans[i] - a[i] * b[i];
        FFT :: DFT(ans, 1);
        for (int i=nt-1; i<ns; ++i) {
            if((int)(ans[i].x-0.5) == 0) printf("%d ", i-nt+2);
        }
        puts("");
        return 0;
    }
    View Code

    可能是noi前最后一次复习FFT了。

  • 相关阅读:
    SQL Cookbook:二、查询结果排序(4)对字母数字混合的数据排序
    (转).net框架读书笔记引用参数(ref/out)
    (转).net面试问答(大汇总)
    SQL Cookbook:一、检索记录(9)限制返回的行数
    C# 3.0 Cookbook:一、字符与字符串处理(5):把一个字符串与另一个字符串的头部或尾部作比较
    (转)sql海量数据优化
    (转)C# 中的委托和事件(二)
    (转)我看微软.NET各技术应用前景
    在sql server数据库中快速删除记录,清空表
    SQL Cookbook:二、查询结果排序(3)按子串排序
  • 原文地址:https://www.cnblogs.com/galaxies/p/20170707_14.html
Copyright © 2020-2023  润新知