• 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() << "
    ";
        for (int i=0; i<l1; ++i) 
            if (ans[i]) printf("%d
    ", i);
        return 0;
    }
    View Code 

    FFT的做法:

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

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

    然后将式子拆开$sumlimits_{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
    ", (int)ans.size());
        for (int i = 0; i < (int)ans.size(); ++i) printf("%d
    ", ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    【JAVA SE基础篇】28.面向对象三大特征之多态
    【JAVA SE基础篇】27.面向对象三大特征之封装
    【JAVA SE基础篇】26.toString()方法和equlas()方法
    【JAVA SE基础篇】25.面向对象三大特征之继承
    【JAVA SE基础篇】24.包的机制和import详解
    ssh框架文件上传下载
    java格式化时间格式
    表单提交后打印后台传过来的数据
    使用ajaxfileupload.js实现文件上传
    JSTL跳出<c:forEach>循环
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9762346.html
Copyright © 2020-2023  润新知