【FFT-Hamming】 UVALIVE 4671 K-neighbor substrings

通道:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2672

题意:两个只包含字符'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 }
View Code

 

posted @ 2015-07-24 16:11  mithrilhan  阅读(407)  评论(0编辑  收藏  举报