【FFT-Hamming】 UVALIVE 4671 K-neighbor substrings
题意:两个只包含字符'a', 'b'的字符串A和B, 求A的子串中与B的Hamming距离不超过K的本质不同的子串数量。
尼玛,卡HASH,这里居然要乘爆才过。
代码:
1 #include <cstdio> 2 #include <cmath> 3 #include <cstring> 4 #include <vector> 5 #include <algorithm> 6 7 using namespace std; 8 9 typedef long long ll; 10 11 const ll MAX_N = 100007; 12 const ll MAX_M = 200007; 13 const double PI = acos(-1.0); 14 15 struct Complex { 16 double r, i; 17 Complex(double _r, double _i) { 18 r = _r; 19 i = _i; 20 } 21 Complex operator + (const Complex &c) { 22 return Complex(c.r + r, c.i + i); 23 } 24 Complex operator - (const Complex &c) { 25 return Complex(r - c.r, i - c.i); 26 } 27 Complex operator * (const Complex &c) { 28 return Complex(c.r * r - c.i * i, c.r * i + c.i * r); 29 } 30 Complex operator / (const int &c) { 31 return Complex(r / c, i / c); 32 } 33 Complex(){} 34 }; 35 namespace FFT { 36 int rev(int id, int len) { 37 int ret = 0; 38 for(int i = 0; (1 << i) < len; ++i) { 39 ret <<= 1; 40 if(id & (1 << i)) ret |= 1; 41 } 42 return ret; 43 } 44 Complex A[MAX_M << 3]; 45 void FFT(Complex *a, int len, int DFT) { 46 for(int i = 0; i < len; ++i) A[rev(i, len)] = a[i]; 47 for(int s = 1; (1 << s) <= len; ++s) { 48 int m = (1 << s); 49 Complex wm = Complex(cos(PI * DFT * 2 / m), sin(PI * DFT * 2 / m)); 50 for(int k = 0; k < len; k += m) { 51 Complex w = Complex(1, 0); 52 for(int j = 0; j < (m >> 1); j++) { 53 Complex t = w * A[k + j + (m >> 1)]; 54 Complex u = A[k + j]; 55 A[k + j] = u + t; 56 A[k + j + (m >> 1)] = u - t; 57 w = w * wm; 58 } 59 } 60 } 61 if(DFT == -1) for(int i = 0; i < len; ++i) A[i] = A[i] / len; 62 for(int i = 0; i < len; i++) a[i] = A[i]; 63 } 64 }; 65 66 #include <set> 67 68 const int MAGIC = 3; 69 const int MOD = (int) 1e9 + 7; 70 71 int K; 72 char a[MAX_N], b[MAX_N]; 73 ll res[MAX_M << 3]; 74 //ll Hash[MAX_N], Pow[MAX_N]; 75 unsigned long long Hash[MAX_N], Pow[MAX_N]; 76 Complex A[MAX_M << 3], B[MAX_M << 3]; 77 set<unsigned long long> s; 78 79 int main() { 80 int cas = 0; 81 Pow[0] = 1; 82 for (int i = 1; i < MAX_N; ++i) Pow[i] = Pow[i - 1] * MAGIC; 83 while (1 == scanf("%d", &K)) { 84 if (-1 == K) break; 85 scanf("%s%s", a, b); 86 printf("Case %d: ", ++cas); 87 int la = strlen(a), lb = strlen(b); 88 if (la < lb) { 89 puts("0"); 90 continue; 91 } 92 if (lb <= K) { 93 printf("%d\n", la - lb + 1); 94 continue; 95 } 96 int len = 1, up = la + lb - 1; 97 while (len <= up) len <<= 1; len <<= 1; 98 for (int i = 0; i < la; ++i) A[i] = Complex(a[i] == 'a' ? 1 : -1, 0); 99 for (int i = la; i < len; ++i) A[i] = Complex(0, 0); 100 for (int i = 0; i < lb; ++i) B[lb - 1 - i] = Complex(b[i] == 'a' ? 1 : -1, 0); 101 for (int i = lb; i < len; ++i) B[i] = Complex(0, 0); 102 FFT::FFT(A, len, 1); FFT::FFT(B, len, 1); 103 for (int i = 0; i < len; ++i) A[i] = A[i] * B[i]; 104 FFT::FFT(A, len, -1); 105 for (int i = 0; i < len; ++i) res[i] = (ll) (A[i].r + 0.5); 106 int limit = lb - K * 2; 107 ll ans = 0; 108 Hash[0] = 0; 109 s.clear(); 110 for (int i = 0; i < la; ++i) Hash[i + 1] = Hash[i] * MAGIC + a[i]; 111 for (int i = lb - 1; i < la; ++i) { 112 unsigned long long now = Hash[i + 1] - Hash[i + 1 - lb] * Pow[lb]; 113 if (s.count(now)) continue; 114 if (res[i] >= limit) { 115 ++ans; 116 s.insert(now); 117 } 118 } 119 printf("%lld\n", ans); 120 } 121 return 0; 122 }