bzoj4503 两个串
题意:给定两个串s,t。其中t可能含有?,可以代表任一字符。
求t在s中一共出现了多少次。
解:
我有个想法是在后缀自动机上DFS,然后发现不记忆化会超时,记忆化又不对。
正解是FFT。我们发现如果把问号看做0,那么两个字符匹配就是(a - b)b = 0
然后整串匹配就是∑(a - b)²b = 0
我们发现这个是顺着来的,不好搞,那么把第二个串reverse,就变成卷积了。
∑a²b - 2ab² + b3 = 0,前两项可以看做是两个卷积,直接卷起来。这时卷积多项式的系数就是串t在s中的某个位置进行匹配的结果。
第三项对于t在s中的任一位置来说都是相同的,直接加。
然后把答案 + 0.5转int就行了,某个位置为0就是答案。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 6 typedef long long LL; 7 const int N = 100010; 8 const double pi = 3.1415926535897932384626, eps = 1e-9; 9 10 struct cp { 11 double x, y; 12 cp(double X = 0.0, double Y = 0.0) { 13 x = X; 14 y = Y; 15 } 16 inline cp operator +(const cp &w) const { 17 return cp(x + w.x, y + w.y); 18 } 19 inline cp operator -(const cp &w) const { 20 return cp(x - w.x, y - w.y); 21 } 22 inline cp operator *(const cp &w) const { 23 return cp(x * w.x - y * w.y, x * w.y + y * w.x); 24 } 25 }a[N << 2], b[N << 2]; 26 27 int r[N << 2]; 28 char s[N], str[N]; 29 double ans[N << 2]; 30 31 inline void FFT(int n, cp *a, int f) { 32 for(int i = 0; i < n; i++) { 33 if(i < r[i]) { 34 std::swap(a[i], a[r[i]]); 35 } 36 } 37 38 for(int len = 1; len < n; len <<= 1) { 39 cp Wn(cos(pi / len), f * sin(pi / len)); 40 for(int i = 0; i < n; i += (len << 1)) { 41 cp w(1, 0); 42 for(int j = 0; j < len; j++) { 43 cp t = a[i + len + j] * w; 44 a[i + len + j] = a[i + j] - t; 45 a[i + j] = a[i + j] + t; 46 w = w * Wn; 47 } 48 } 49 } 50 51 if(f == -1) { 52 for(int i = 0; i <= n; i++) { 53 a[i].x /= n; 54 } 55 } 56 return; 57 } 58 59 int main() { 60 61 scanf("%s%s", s, str); 62 int n = strlen(s) - 1, m = strlen(str) - 1; 63 LL b3 = 0; 64 for(int i = 0; i <= n; i++) { 65 a[i].x = (s[i] - 'a' + 1) * (s[i] - 'a' + 1); 66 } 67 for(int i = 0; i <= m; i++) { 68 if(str[i] == '?') { 69 b[m - i].x = 0; 70 } 71 else { 72 b[m - i].x = (str[i] - 'a' + 1); 73 b3 += (str[i] - 'a' + 1) * (str[i] - 'a' + 1) * (str[i] - 'a' + 1); 74 } 75 } 76 77 int len = 2, lm = 1; 78 while(len <= n + m) { 79 len <<= 1; 80 lm++; 81 } 82 for(int i = 1; i <= len; i++) { 83 r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1)); 84 } 85 86 FFT(len, a, 1); 87 FFT(len, b, 1); 88 for(int i = 0; i <= len; i++) { 89 a[i] = a[i] * b[i]; 90 } 91 FFT(len, a, -1); 92 for(int i = 0; i <= len; i++) { 93 ans[i] = a[i].x; 94 } 95 96 for(int i = 0; i <= n; i++) { 97 a[i].x = 2 * (s[i] - 'a' + 1); 98 a[i].y = 0; 99 } 100 for(int i = n + 1; i <= len; i++) { 101 a[i].x = a[i].y = 0; 102 } 103 for(int i = 0; i <= m; i++) { 104 if(str[i] == '?') { 105 b[m - i].x = 0; 106 } 107 else { 108 b[m - i].x = (str[i] -'a' + 1) * (str[i] - 'a' + 1); 109 } 110 b[m - i].y = 0; 111 } 112 for(int i = m + 1; i <= len; i++) { 113 b[i].x = b[i].y = 0; 114 } 115 FFT(len, a, 1); 116 FFT(len, b, 1); 117 for(int i = 0; i <= len; i++) { 118 a[i] = a[i] * b[i]; 119 } 120 FFT(len, a, -1); 121 for(int i = 0; i <= len; i++) { 122 ans[i] -= a[i].x; 123 } 124 125 for(int i = 0; i <= len; i++) { 126 ans[i] += b3; 127 } 128 129 int temp = 0; 130 for(int i = m; i <= n; i++) { 131 temp += int(ans[i] + 0.5) == 0; 132 } 133 printf("%d\n", temp); 134 for(int i = m; i <= n; i++) { 135 if(int(ans[i] + 0.5) == 0) { 136 printf("%d\n", i - m); 137 } 138 } 139 return 0; 140 }
双倍经验:BZOJ4259
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 #include <cstring> 5 6 const int N = 300010; 7 const double pi = 3.1415926535897932384626; 8 9 struct cp { 10 double x, y; 11 cp(double X = 0, double Y = 0) { 12 x = X; 13 y = Y; 14 } 15 inline cp operator +(const cp &w) const { 16 return cp(x + w.x, y + w.y); 17 } 18 inline cp operator -(const cp &w) const { 19 return cp(x - w.x, y - w.y); 20 } 21 inline cp operator *(const cp &w) const { 22 return cp(x * w.x - y * w.y, x * w.y + y * w.x); 23 } 24 }a[N << 2], b[N << 2]; 25 26 int r[N << 2]; 27 char s[N], str[N]; 28 double ans[N << 2]; 29 30 inline void FFT(int n, cp *a, int f) { 31 for(int i = 0; i < n; i++) { 32 if(i < r[i]) { 33 std::swap(a[i], a[r[i]]); 34 } 35 } 36 37 for(int len = 1; len < n; len <<= 1) { 38 cp Wn(cos(pi / len), f * sin(pi / len)); 39 for(int i = 0; i < n; i += (len << 1)) { 40 cp w(1, 0); 41 for(int j = 0; j < len; j++) { 42 cp t = a[i + len + j] * w; 43 a[i + len + j] = a[i + j] - t; 44 a[i + j] = a[i + j] + t; 45 w = w * Wn; 46 } 47 } 48 } 49 50 if(f == -1) { 51 for(int i = 0; i <= n; i++) { 52 a[i].x /= n; 53 } 54 } 55 return; 56 } 57 58 int main() { 59 int m, n; 60 scanf("%d%d", &m, &n); 61 m--; 62 n--; 63 scanf("%s%s", str, s); 64 for(int i = 0; i <= n; i++) { 65 s[i] = (s[i] == '*' ? 0 : s[i] - 'a' + 1); 66 } 67 for(int i = 0; i <= m; i++) { 68 str[i] = (str[i] == '*' ? 0 : str[i] - 'a' + 1); 69 } 70 int len = 2, lm = 1; 71 while(len <= n + m) { 72 len <<= 1; 73 lm++; 74 } 75 for(int i = 1; i <= len; i++) { 76 r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1)); 77 } 78 79 for(int i = 0; i <= n; i++) { 80 a[i] = cp(1ll * s[i] * s[i] * s[i], 0); 81 } 82 for(int i = 0; i <= m; i++) { 83 b[i] = cp(str[m - i], 0); 84 } 85 FFT(len, a, 1); 86 FFT(len, b, 1); 87 for(int i = 0; i <= len; i++) { 88 a[i] = a[i] * b[i]; 89 } 90 FFT(len, a, -1); 91 for(int i = 0; i <= len; i++) { 92 ans[i] = a[i].x; 93 } 94 95 for(int i = 0; i <= n; i++) { 96 a[i] = cp(1ll * s[i] * s[i], 0); 97 } 98 for(int i = 0; i <= m; i++) { 99 b[i] = cp(1ll * str[m - i] * str[m - i], 0); 100 } 101 for(int i = n + 1; i <= len; i++) { 102 a[i] = cp(0, 0); 103 } 104 for(int i = m + 1; i <= len; i++) { 105 b[i] = cp(0, 0); 106 } 107 FFT(len, a, 1); 108 FFT(len, b, 1); 109 for(int i = 0; i <= len; i++) { 110 a[i] = a[i] * b[i]; 111 } 112 FFT(len, a, -1); 113 for(int i = 0; i <= len; i++) { 114 ans[i] -= 2 * a[i].x; 115 } 116 117 for(int i = 0; i <= n; i++) { 118 a[i] = cp(s[i], 0); 119 } 120 for(int i = 0; i <= m; i++) { 121 b[i] = cp(1ll * str[m - i] * str[m - i] * str[m - i], 0); 122 } 123 for(int i = n + 1; i <= len; i++) { 124 a[i] = cp(0, 0); 125 } 126 for(int i = m + 1; i <= len; i++) { 127 b[i] = cp(0, 0); 128 } 129 FFT(len, a, 1); 130 FFT(len, b, 1); 131 for(int i = 0; i <= len; i++) { 132 a[i] = a[i] * b[i]; 133 } 134 FFT(len, a, -1); 135 for(int i = 0; i <= len; i++) { 136 ans[i] += a[i].x; 137 } 138 139 int temp = 0; 140 for(int i = m; i <= n; i++) { 141 temp += (int)(ans[i] + 0.5) == 0; 142 } 143 printf("%d\n", temp); 144 for(int i = m; i <= n; i++) { 145 if((int)(ans[i] + 0.5) == 0) { 146 printf("%d ", i - m + 1); 147 } 148 } 149 return 0; 150 }