【FFT+KMP】 URAL1996 Cipher Message 3
通道:http://acm.timus.ru/problem.aspx?space=1&num=1996
题意:两个串A B,每个串是若干个byte,A串的每个byte的最后一个bit是可以修改的。问最少修改多少,使得B串是A的一个子串
思路:前七位KMP,后面一位NlgN的hamming distance,将两个01串a , b。将b反转之后,求一次卷积,便可以得到a串中以i为起始位置,与b进行匹配有多少个位置同为1,那么接下来把a,b的值01反转一下,再求一次卷积,便可以得到a串中以i为起始位置,与b进行匹配有多少个位置同为0
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 int MAX_N = 300007; 12 const int MAX_M = 300007; 13 const long double PI = acos(-1.0); 14 15 struct Complex { 16 long double r, i; 17 Complex(long double _r, long 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 int n, m; 67 int a[MAX_N], b[MAX_N], p[MAX_N], e[MAX_N]; 68 vector<int> pos; 69 Complex A[MAX_M << 3], B[MAX_M << 3]; 70 71 void getFail() { 72 int j = 0; 73 p[1] = 0; 74 for (int i = 2; i <= m; ++i) { 75 while (j > 0 && (b[j + 1] >> 1) != (b[i] >> 1)) j = p[j]; 76 if ((b[j + 1] >> 1) == (b[i] >> 1)) ++j; 77 p[i] = j; 78 } 79 } 80 81 void KMP() { 82 getFail(); 83 int j = 0; 84 for (int i = 1; i <= n; ++i) { 85 while (j > 0 && (b[j + 1] >> 1) != (a[i] >> 1)) j = p[j]; 86 if ((b[j + 1] >> 1) == (a[i] >> 1)) ++j; 87 if (j == m) { 88 pos.push_back(i - m + 1); 89 j = p[j]; 90 } 91 } 92 } 93 94 int main() { 95 while (2 == scanf("%d%d", &n, &m)) { 96 for (int i = 1; i <= n; ++i) { 97 char str[10]; scanf("%s", str); a[i] = 0; 98 for (int j = 0; j < 8; ++j) a[i] <<= 1, a[i] |= str[j] - '0'; 99 } 100 for (int i = 1; i <= m; ++i) { 101 char str[10]; scanf("%s", str); b[i] = 0; 102 for (int j = 0; j < 8; ++j) b[i] <<= 1, b[i] |= str[j] - '0'; 103 } 104 if (n < m) { 105 puts("No"); continue; 106 } 107 pos.clear(); 108 KMP(); 109 if (pos.size() == 0) { 110 puts("No"); continue; 111 } 112 int len = 1; 113 while (len <= n) len <<= 1; len <<= 1; 114 for (int i = 1; i <= n; ++i) A[i - 1] = Complex(a[i] & 1, 0); 115 for (int i = n; i < len; ++i) A[i] = Complex(0, 0); 116 for (int i = 1; i <= m; ++i) B[i - 1] = Complex(b[m - i + 1] & 1, 0); 117 for (int i = m; i < len; ++i) B[i] = Complex(0, 0); 118 FFT::FFT(A, len, 1); FFT::FFT(B, len, 1); 119 for (int i = 0; i < len; ++i) A[i] = A[i] * B[i]; 120 FFT::FFT(A, len, -1); 121 memset(e, 0, sizeof e); 122 for (int i = 0; i < n - m + 1; ++i) e[i] = m - (int)(A[i + m - 1].r + 0.5); 123 124 for (int i = 1; i <= n; ++i) A[i - 1] = Complex(a[i] & 1 ^ 1, 0); 125 for (int i = n; i < len; ++i) A[i] = Complex(0, 0); 126 for (int i = 1; i <= m; ++i) B[i - 1] = Complex(b[m - i + 1] & 1 ^ 1, 0); 127 for (int i = m; i < len; ++i) B[i] = Complex(0, 0); 128 FFT::FFT(A, len, 1); FFT::FFT(B, len, 1); 129 for (int i = 0; i < len; ++i) A[i] = A[i] * B[i]; 130 FFT::FFT(A, len, -1); 131 for (int i = 0; i < n - m + 1; ++i) e[i] -= (int)(A[i + m - 1].r + 0.5); 132 int id = -1, step = 1e9 + 7; 133 puts("Yes"); 134 for(int i = 0, sz = pos.size(); i < sz; ++i) if(step > e[pos[i] - 1]) 135 step = e[pos[i] - 1], id = pos[i]; 136 printf("%d %d\n", step, id); 137 } 138 return 0; 139 }