• 2021航电多校3


    题解

    经典的卷积求字符串匹配问题,但是我看错题+太菜,没想到用FTT做。

    先忽略通配符的影响,分字符计算出每个起点的最大匹配字符个数,卷积的时候让T串逆序即可。

    考虑通配符的贡献,贡献为S中通配符的个数 + T中通配符的个数 - S和T中对应位置都是通配符的个数。前两项可以用前缀和计算,后一项可以用FTT计算。

    注意FTT使用非递归写法,递归写法容易T。

    #include <bits/stdc++.h>
    #include <cmath>
    #include <complex>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N)
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {
        return b ? gcd(b, a % b) : a;
    }
    #define INF 0x3f3f3f3f
    double PI = acos(-1);
    
    
    typedef std::complex<double> Comp;  // STL complex
    
    const Comp I(0, 1);  // i
    const int N = 2e6;
    
    Comp tmp[N];
    Comp f1[N], f2[N];
    int rev[N];
    
    
    void change(Comp y[], int len) {
      for (int i = 0; i < len; ++i) {
        rev[i] = rev[i >> 1] >> 1;
        if (i & 1) {  // 如果最后一位是 1,则翻转成 len/2
          rev[i] |= len >> 1;
        }
      }
      for (int i = 0; i < len; ++i) {
        if (i < rev[i]) {  // 保证每对数只翻转一次
          swap(y[i], y[rev[i]]);
        }
      }
      return;
    }
    
    void fft(Comp y[], int len, int on) {
      change(y, len);
      for (int h = 2; h <= len; h <<= 1) {                  // 模拟合并过程
        Comp wn(cos(2 * PI / h), sin(on * 2 * PI / h));  // 计算当前单位复根
        for (int j = 0; j < len; j += h) {
          Comp w(1, 0);  // 计算当前单位复根
          for (int k = j; k < j + h / 2; k++) {
            Comp u = y[k];
            Comp t = w * y[k + h / 2];
            y[k] = u + t;  // 这就是把两部分分治的结果加起来
            y[k + h / 2] = u - t;
            // 后半个 “step” 中的ω一定和 “前半个” 中的成相反数
            // “红圈”上的点转一整圈“转回来”,转半圈正好转成相反数
            // 一个数相反数的平方与这个数自身的平方相等
            w = w * wn;
          }
        }
      }
      if (on == -1) {
        for (int i = 0; i < len; i++) {
          y[i] /= len;
        }
      }
    }
    
    int get(int x) {
        int res = 1;
        while(res < x) 
            res = (res << 1);
        return res;
    }
    
    char s1[N], s2[N];
    int spre[N], ssum, scount[N];
    
    void init(int len) {
        for(int i = 0; i <= len; i++) {
            f1[i] = f2[i] = Comp(0, 0);
        }
    }
    
    int ans[N];
    int res[N];
    
    int main() {
        IOS;
        int k;
        cin >> k;
        while(k--) {
            int n, m;
            cin >> n >> m;
            for(int i = 0; i < n; i++) ans[i] = res[i] = 0;
            int len = get(max(n, m));
            init(len);
            cin >> s1 >> s2;
            reverse(s2, s2 + m);
            
            ssum = 0;
            for(int i = 0; i < n; i++) {
                spre[i] = 0;
                if(s1[i] == '*') {
                    spre[i] = 1;
                    f1[i] = Comp(1, 0);
                }
                spre[i] += spre[i - 1];
            }
            for(int i = 0; i < m; i++) {
                if(s2[i] == '*') {
                    ssum++;
                    f2[i] = Comp(1, 0);
                }
            }
    
            fft(f1, len, 1);
            fft(f2, len, 1);
            for(int i = 0; i < len; i++) {
                f1[i] *= f2[i];
            }
            fft(f1, len, -1);
            for(int i = 0; i < len; i++) {
                scount[i] = (int)round(f1[i].real());
            }
            
            
            for(int i = 0; i < 10; i++) {
                init(len);
                for(int j = 0; j < n; j++) {
                    if(s1[j] == i + '0') {
                        f1[j] = Comp(1, 0);
                    }
                }
                for(int j = 0; j < m; j++) {
                    if(s2[j] == i + '0') {
                        f2[j] = Comp(1, 0);
                    }
                }
                fft(f1, len, 1);
                fft(f2, len, 1);
                for(int j = 0; j < len; j++) {
                    f1[j] *= f2[j];
                }
                fft(f1, len, -1);
                for(int j = m - 1; j < n; j++) {
                    ans[j] += (int)round(f1[j].real());
                }
            }
            
            for(int i = m - 1; i < n; i++) {
                ans[i] += (spre[i] + ssum - scount[i]);
                if(i - m >= 0) ans[i] -= spre[i - m];
                assert(m - ans[i] >= 0);
                res[m - ans[i]]++;
            }
    
            for(int i = 1; i <= m; i++) {
                res[i] += res[i - 1];
            }
            for(int i = 0; i <= m; i++) {
                cout << res[i] << endl;
            }
        }
    }
    
  • 相关阅读:
    函数响应式编程及ReactiveObjC学习笔记 (-)
    Flask的第一个应用
    Django错误 OperationalError: no such column: xxx
    Python高级数据类型模块collections
    wsgiref 源码解析
    WSGI文档(中文版)
    Python:树的遍历
    Django+haystack实现全文搜索出现错误 ImportError: cannot import name signals
    Django+Celery+Redis实现异步任务(发送邮件)
    Python面向对象—类的继承
  • 原文地址:https://www.cnblogs.com/limil/p/15089119.html
Copyright © 2020-2023  润新知