一开始看错题了,看了好久才发现就是个板子。。。
这个东西本质上是循环移位,我们考虑在 \(S\) 前后各添加 \(W - 1\) 个 .
,例如 \(W = 5, S = \texttt{ABC}\) 时,添加后 \(S = \texttt{....ABC....}\)。此时我们发现 \(S\) 的每个长度为 \(W\) 的子串一一对应一个显示在公告板上的串。那么这就是一个带通配符字符串匹配问题。
接下来直接套 P4173 残缺的字符串即可。展开讲的话,设 \(n = |s|, m = |t|\),并且 \(t\) 要匹配 \(s\)。那我们把通配符的值设成 \(0\) 后,设 \(f_i = \sum\limits_{j = 1}^m t_j (s_{i - m + j} - t_j)^2\),那么 \(s_{i - m + 1 \sim i}\) 能匹配 \(t\) 当且仅当 \(f_i = 0\)。把平方拆开,就是若干个减法卷积。考虑翻转 \(t\),做加法卷积即可。
时间复杂度是 \(O(n \log n)\),带一个巨大常数。
这题用 NTT 会有些难受,因为 \(f_i\) 能达到 \(5 \times 10^9\),为了保证正确性必须要写双模数(我写的双模数还 T 了),FFT 比 NTT 快很多(可能是我 NTT 的实现劣了),所以我使用的是 FFT。
code
// Problem: Ex - Marquee
// Contest: AtCoder - Tokio Marine & Nichido Fire Insurance Programming Contest 2023(AtCoder Beginner Contest 307)
// URL: https://atcoder.jp/contests/abc307/tasks/abc307_h
// Memory Limit: 1024 MB
// Time Limit: 5000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 2100100;
const db pi = acos(-1);
int n, m, mp[128], a[maxn], b[maxn], r[maxn];
db f[maxn], g[maxn];
char s[maxn], t[maxn];
struct comp {
db x, y;
comp(db a = 0, db b = 0) : x(a), y(b) {}
};
typedef vector<comp> poly;
inline comp operator + (const comp &a, const comp &b) {
return comp(a.x + b.x, a.y + b.y);
}
inline comp operator - (const comp &a, const comp &b) {
return comp(a.x - b.x, a.y - b.y);
}
inline comp operator * (const comp &a, const db &b) {
return comp(a.x * b, a.y * b);
}
inline comp operator / (const comp &a, const db &b) {
return comp(a.x / b, a.y / b);
}
inline comp operator * (const comp &a, const comp &b) {
return comp(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
}
typedef vector<comp> poly;
inline poly FFT(poly a, int op) {
int n = (int)a.size();
for (int i = 0; i < n; ++i) {
if (i < r[i]) {
swap(a[i], a[r[i]]);
}
}
for (int k = 1; k < n; k <<= 1) {
comp wn(cos(pi / k), sin(pi / k) * op);
for (int i = 0; i < n; i += (k << 1)) {
comp w(1, 0);
for (int j = 0; j < k; ++j, w = w * wn) {
comp x = a[i + j], y = w * a[i + j + k];
a[i + j] = x + y;
a[i + j + k] = x - y;
}
}
}
if (op == -1) {
for (int i = 0; i < n; ++i) {
a[i] = a[i] / n;
}
}
return a;
}
inline poly operator * (poly a, poly b) {
a = FFT(a, 1);
b = FFT(b, 1);
int n = (int)a.size();
for (int i = 0; i < n; ++i) {
a[i] = a[i] * b[i];
}
a = FFT(a, -1);
return a;
}
void solve() {
scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
if (m == 1) {
puts(t[1] == '_' || s[1] == t[1] ? "1" : "0");
return;
}
mp['_'] = 0;
mp['.'] = 1;
int ntot = 1;
for (char c = 'a'; c <= 'z'; ++c) {
mp[c] = ++ntot;
}
for (char c = 'A'; c <= 'Z'; ++c) {
mp[c] = ++ntot;
}
int _n = n;
n = -1;
for (int i = 1; i < m; ++i) {
a[++n] = 1;
}
for (int i = 1; i <= _n; ++i) {
a[++n] = mp[s[i]];
}
for (int i = 1; i < m; ++i) {
a[++n] = 1;
}
--m;
for (int i = 0; i <= m; ++i) {
b[i] = mp[t[i + 1]];
}
int k = 0;
while ((1 << k) <= n + m) {
++k;
}
for (int i = 1; i < (1 << k); ++i) {
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
}
reverse(b, b + m + 1);
poly A(1 << k), B(1 << k);
for (int i = 0; i <= n; ++i) {
A[i] = comp(a[i] * a[i], 0);
}
for (int i = 0; i <= m; ++i) {
B[i] = comp(b[i], 0);
}
poly C = A * B;
for (int i = m; i <= n; ++i) {
f[i] += C[i].x;
}
A = poly(1 << k);
B = poly(1 << k);
for (int i = 0; i <= n; ++i) {
A[i] = comp(-2 * a[i], 0);
}
for (int i = 0; i <= m; ++i) {
B[i] = comp(b[i] * b[i], 0);
}
C = A * B;
for (int i = m; i <= n; ++i) {
f[i] += C[i].x;
}
ll s = 0;
for (int i = 0; i <= m; ++i) {
s += b[i] * b[i] * b[i];
}
for (int i = m; i <= n; ++i) {
f[i] += s;
}
int ans = 0;
for (int i = m; i <= n; ++i) {
ans += (fabs(f[i]) < 0.4);
}
printf("%d\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}
- Beginner AtCoder Contest Marquee 307beginner atcoder contest 307 beginner atcoder contest marquee contest programming beginner atcoder beginner atcoder contest 296 beginner atcoder contest 295 beginner atcoder contest abcde beginner atcoder contest 335 beginner atcoder contest 328 beginner atcoder contest 334 beginner atcoder contest 332