bzoj4503 两个串

本文介绍了如何运用快速傅立叶变换(FFT)解决bzoj4503题目,该题目涉及字符串匹配。通过将字符串转换为数值,将匹配问题转化为卷积计算,通过三次FFT运算得出结果。由于T串含有问号,计算时不需考虑相应项,从而简化了计算过程。
摘要由CSDN通过智能技术生成

两个串

题目背景:

bzoj4503

分析:

我相信各路大牛在看到这道题的时候一定会不屑的表示这个不是套路题吗····的确这真心就是一个简单的套路,快速傅立叶变换(FFT),我们选择将T进行翻转,然后令

c[j + m – 1] = sigma((a[j + i] – b[m – 1 – i]) ^ 2* a[j + i] * b[m – 1 – i]) (0 <= i < m)

其中的mT的长度,a[i]表示S的第i个字符,b[i]T的第i个字符,为了方便计算我们把a看作1b看作2,以此类推,并且把?看作是记作,然后我们就可以发现当c[j + m – 1] = 0当且仅当S从第j个位置开始就可以匹配上T,、我们直接计算T就可以了,然后,我们注意到上面的计算式实际上是三个卷积形式,分别为a ^ 3 * b, 2 * a ^ 2 * b ^ 2, a * b ^ 3 (a, b表示对应的数组的中的元素然后直接进行三次FFT即可,板子一定要敲对·····

注意:因为这一道题中只有T串中是有?的,所以其实我们可以在最后少乘一个a[j + i],本人的代码中就并没有乘上这一步。

Source

#include 
   
   
    
    
#include 
    
    
     
     
#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
         #include 
        
          using namespace std; const int MAXN = 400000 + 30; const double PI2 = acos(-1.0) * 2; struct Complex { double r, i; Complex(double r = 0, double i = 0) : r(r), i(i) {} inline Complex operator + (const Complex &a) { return Complex(r + a.r, i + a.i); } inline Complex operator - (const Complex &a) { return Complex(r - a.r, i - a.i); } inline Complex operator * (const Complex &a) { return Complex(r * a.r - i * a.i, r * a.i + i * a.r); } inline Complex conj() { return Complex(r, -i); } } a[MAXN], b[MAXN], c[MAXN], d[MAXN]; struct FFT { int k, pos[MAXN]; inline void init(int m, int n) { for (k = 1, m += n; k <= m; k <<= 1); for (int i = 1; i < k; ++i) pos[i] = (i & 1) ? (pos[i >> 1] >> 1) ^ (k >> 1) : (pos[i >> 1] >> 1); } inline void fft(Complex *a, const int n, const int t) { for (int i = 1; i < n; ++i) if (i < pos[i]) swap(a[i], a[pos[i]]); for (int m2, m1 = 1; m1 < n; m1 <<= 1) { m2 = m1 << 1; double temp = PI2 / m2 * t; Complex wn(cos(temp), sin(temp)); for (int i = 0; i < n; i += m2) { Complex w(1, 0); for (int j = 0; j < m1; ++j) { Complex &A = a[i + j + m1], &B = a[i + j], t = w * A; A = B - t, B = B + t, w = w * wn; } } } if (t == -1) for (int i = 0; i < n; ++i) a[i].r /= n; } inline void muitiply(Complex *a, Complex *b, Complex *c) { fft(a, k, 1), fft(b, k, 1); for (int i = 0; i < k; ++i) c[i] = a[i] * b[i]; fft(c, k, -1); } } fft; string str1, str2; int s1[MAXN], s2[MAXN]; inline int change(char c) { if (c >= 'a' && c <= 'z') return c - 'a' + 1; else return 0; } inline void work() { cin >> str1 >> str2; int m = str1.size(), n = str2.size(); for (int i = 0; i < m; ++i) s1[i] = change(str1[i]); for (int i = 0; i < n; ++i) s2[i] = change(str2[n - i - 1]); fft.init(m, n); for (int i = 0; i < fft.k; ++i) a[i] = Complex(s1[i] * s1[i], 0); for (int i = 0; i < fft.k; ++i) b[i] = Complex(s2[i], 0); fft.fft(a, fft.k, 1), fft.fft(b, fft.k, 1); for (int i = 0; i < fft.k; ++i) c[i] = c[i] + a[i] * b[i]; for (int i = 0; i < fft.k; ++i) a[i] = Complex(s1[i] * 2, 0); for (int i = 0; i < fft.k; ++i) b[i] = Complex(s2[i] * s2[i], 0); fft.fft(a, fft.k, 1), fft.fft(b, fft.k, 1); for (int i = 0; i < fft.k; ++i) c[i] = c[i] - a[i] * b[i]; for (int i = 0; i < fft.k; ++i) a[i] = Complex(1, 0); for (int i = 0; i < fft.k; ++i) b[i] = Complex(s2[i] * s2[i] * s2[i], 0); fft.fft(a, fft.k, 1), fft.fft(b, fft.k, 1); for (int i = 0; i < fft.k; ++i) c[i] = c[i] + a[i] * b[i]; fft.fft(c, fft.k, -1); int cnt = 0; for (int i = 0; i < m - n + 1; ++i) if (c[i + n - 1].r < 0.5) cnt++; cout << cnt << '\n'; for (int i = 0; i < m - n + 1; ++i) if (c[i + n - 1].r < 0.5) cout << i << '\n'; } int main() { work(); return 0; } 
         
       
      
      
     
     
    
    
   
   

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值