#pragma GCC optimize("O3,unroll-loops") #pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt") #line 1 "template/template.hpp" #include using namespace std; using int64 = long long; const int mod = 998244353; const int64 infll = (1LL << 62) - 1; const int inf = (1 << 30) - 1; struct IoSetup { IoSetup() { cin.tie(nullptr); ios::sync_with_stdio(false); cout << fixed << setprecision(10); cerr << fixed << setprecision(10); } } iosetup; template< typename T1, typename T2 > ostream &operator<<(ostream &os, const pair< T1, T2 > &p) { os << p.first << " " << p.second; return os; } template< typename T1, typename T2 > istream &operator>>(istream &is, pair< T1, T2 > &p) { is >> p.first >> p.second; return is; } template< typename T > ostream &operator<<(ostream &os, const vector< T > &v) { for (int i = 0; i < (int) v.size(); i++) { os << v[i] << (i + 1 != v.size() ? " " : ""); } return os; } template< typename T > istream &operator>>(istream &is, vector< T > &v) { for (T &in: v) is >> in; return is; } template< typename T1, typename T2 > inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); } template< typename T1, typename T2 > inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); } template< typename T = int64 > vector< T > make_v(size_t a) { return vector< T >(a); } template< typename T, typename... Ts > auto make_v(size_t a, Ts... ts) { return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...)); } template< typename T, typename V > typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) { t = v; } template< typename T, typename V > typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) { for (auto &e: t) fill_v(e, v); } template< typename F > struct FixPoint: F { explicit FixPoint(F &&f): F(forward< F >(f)) {} template< typename... Args > decltype(auto) operator()(Args &&... args) const { return F::operator()(*this, forward< Args >(args)...); } }; template< typename F > inline decltype(auto) MFP(F &&f) { return FixPoint< F >{forward< F >(f)}; } template< typename Mint > struct NumberTheoreticTransformFriendlyModInt { static vector< Mint > roots, iroots, rate3, irate3; static int max_base; NumberTheoreticTransformFriendlyModInt() = default; static void init() { if (roots.empty()) { const unsigned mod = Mint::get_mod(); assert(mod >= 3 && mod % 2 == 1); auto tmp = mod - 1; max_base = 0; while (tmp % 2 == 0) tmp >>= 1, max_base++; Mint root = 2; while (root.pow((mod - 1) >> 1) == 1) { root += 1; } assert(root.pow(mod - 1) == 1); roots.resize(max_base + 1); iroots.resize(max_base + 1); rate3.resize(max_base + 1); irate3.resize(max_base + 1); roots[max_base] = root.pow((mod - 1) >> max_base); iroots[max_base] = Mint(1) / roots[max_base]; for (int i = max_base - 1; i >= 0; i--) { roots[i] = roots[i + 1] * roots[i + 1]; iroots[i] = iroots[i + 1] * iroots[i + 1]; } { Mint prod = 1, iprod = 1; for (int i = 0; i <= max_base - 3; i++) { rate3[i] = roots[i + 3] * prod; irate3[i] = iroots[i + 3] * iprod; prod *= iroots[i + 3]; iprod *= roots[i + 3]; } } } } static void ntt(vector< Mint > &a) { init(); const int n = (int) a.size(); assert((n & (n - 1)) == 0); int h = __builtin_ctz(n); assert(h <= max_base); int len = 0; Mint imag = roots[2]; if (h & 1) { int p = 1 << (h - 1); Mint rot = 1; for (int i = 0; i < p; i++) { auto r = a[i + p]; a[i + p] = a[i] - r; a[i] += r; } len++; } for (; len + 1 < h; len += 2) { int p = 1 << (h - len - 2); { // s = 0 for (int i = 0; i < p; i++) { auto a0 = a[i]; auto a1 = a[i + p]; auto a2 = a[i + 2 * p]; auto a3 = a[i + 3 * p]; auto a1na3imag = (a1 - a3) * imag; auto a0a2 = a0 + a2; auto a1a3 = a1 + a3; auto a0na2 = a0 - a2; a[i] = a0a2 + a1a3; a[i + 1 * p] = a0a2 - a1a3; a[i + 2 * p] = a0na2 + a1na3imag; a[i + 3 * p] = a0na2 - a1na3imag; } } Mint rot = rate3[0]; for (int s = 1; s < (1 << len); s++) { int offset = s << (h - len); Mint rot2 = rot * rot; Mint rot3 = rot2 * rot; for (int i = 0; i < p; i++) { auto a0 = a[i + offset]; auto a1 = a[i + offset + p] * rot; auto a2 = a[i + offset + 2 * p] * rot2; auto a3 = a[i + offset + 3 * p] * rot3; auto a1na3imag = (a1 - a3) * imag; auto a0a2 = a0 + a2; auto a1a3 = a1 + a3; auto a0na2 = a0 - a2; a[i + offset] = a0a2 + a1a3; a[i + offset + 1 * p] = a0a2 - a1a3; a[i + offset + 2 * p] = a0na2 + a1na3imag; a[i + offset + 3 * p] = a0na2 - a1na3imag; } rot *= rate3[__builtin_ctz(~s)]; } } } static void intt(vector< Mint > &a, bool f = true) { init(); const int n = (int) a.size(); assert((n & (n - 1)) == 0); int h = __builtin_ctz(n); assert(h <= max_base); int len = h; Mint iimag = iroots[2]; for (; len > 1; len -= 2) { int p = 1 << (h - len); { // s = 0 for (int i = 0; i < p; i++) { auto a0 = a[i]; auto a1 = a[i + 1 * p]; auto a2 = a[i + 2 * p]; auto a3 = a[i + 3 * p]; auto a2na3iimag = (a2 - a3) * iimag; auto a0na1 = a0 - a1; auto a0a1 = a0 + a1; auto a2a3 = a2 + a3; a[i] = a0a1 + a2a3; a[i + 1 * p] = (a0na1 + a2na3iimag); a[i + 2 * p] = (a0a1 - a2a3); a[i + 3 * p] = (a0na1 - a2na3iimag); } } Mint irot = irate3[0]; for (int s = 1; s < (1 << (len - 2)); s++) { int offset = s << (h - len + 2); Mint irot2 = irot * irot; Mint irot3 = irot2 * irot; for (int i = 0; i < p; i++) { auto a0 = a[i + offset]; auto a1 = a[i + offset + 1 * p]; auto a2 = a[i + offset + 2 * p]; auto a3 = a[i + offset + 3 * p]; auto a2na3iimag = (a2 - a3) * iimag; auto a0na1 = a0 - a1; auto a0a1 = a0 + a1; auto a2a3 = a2 + a3; a[i + offset] = a0a1 + a2a3; a[i + offset + 1 * p] = (a0na1 + a2na3iimag) * irot; a[i + offset + 2 * p] = (a0a1 - a2a3) * irot2; a[i + offset + 3 * p] = (a0na1 - a2na3iimag) * irot3; } irot *= irate3[__builtin_ctz(~s)]; } } if (len >= 1) { int p = 1 << (h - 1); for (int i = 0; i < p; i++) { auto ajp = a[i] - a[i + p]; a[i] += a[i + p]; a[i + p] = ajp; } } if (f) { Mint inv_sz = Mint(1) / n; for (int i = 0; i < n; i++) a[i] *= inv_sz; } } static vector< Mint > multiply(vector< Mint > a, vector< Mint > b) { int need = a.size() + b.size() - 1; int nbase = 1; while ((1 << nbase) < need) nbase++; int sz = 1 << nbase; a.resize(sz, 0); b.resize(sz, 0); ntt(a); ntt(b); Mint inv_sz = Mint(1) / sz; for (int i = 0; i < sz; i++) a[i] *= b[i] * inv_sz; intt(a, false); a.resize(need); return a; } }; template< typename Mint > vector< Mint > NumberTheoreticTransformFriendlyModInt< Mint >::roots = vector< Mint >(); template< typename Mint > vector< Mint > NumberTheoreticTransformFriendlyModInt< Mint >::iroots = vector< Mint >(); template< typename Mint > vector< Mint > NumberTheoreticTransformFriendlyModInt< Mint >::rate3 = vector< Mint >(); template< typename Mint > vector< Mint > NumberTheoreticTransformFriendlyModInt< Mint >::irate3 = vector< Mint >(); template< typename Mint > int NumberTheoreticTransformFriendlyModInt< Mint >::max_base = 0; template< uint32_t mod, bool fast = false > struct MontgomeryModInt { using mint = MontgomeryModInt; using i32 = int32_t; using i64 = int64_t; using u32 = uint32_t; using u64 = uint64_t; static constexpr u32 get_r() { u32 ret = mod; for (i32 i = 0; i < 4; i++) ret *= 2 - mod * ret; return ret; } static constexpr u32 r = get_r(); static constexpr u32 n2 = -u64(mod) % mod; static_assert(r * mod == 1, "invalid, r * mod != 1"); static_assert(mod < (1 << 30), "invalid, mod >= 2 ^ 30"); static_assert((mod & 1) == 1, "invalid, mod % 2 == 0"); u32 x; MontgomeryModInt(): x{} {} MontgomeryModInt(const i64 &a) : x(reduce(u64(fast ? a : (a % mod + mod)) * n2)) {} static constexpr u32 reduce(const u64 &b) { return u32(b >> 32) + mod - u32((u64(u32(b) * r) * mod) >> 32); } mint &operator+=(const mint &p) { if (i32(x += p.x - 2 * mod) < 0) x += 2 * mod; return *this; } mint &operator-=(const mint &p) { if (i32(x -= p.x) < 0) x += 2 * mod; return *this; } mint &operator*=(const mint &p) { x = reduce(u64(x) * p.x); return *this; } mint &operator/=(const mint &p) { *this *= p.inverse(); return *this; } mint operator-() const { return mint() - *this; } mint operator+(const mint &p) const { return mint(*this) += p; } mint operator-(const mint &p) const { return mint(*this) -= p; } mint operator*(const mint &p) const { return mint(*this) *= p; } mint operator/(const mint &p) const { return mint(*this) /= p; } bool operator==(const mint &p) const { return (x >= mod ? x - mod : x) == (p.x >= mod ? p.x - mod : p.x); } bool operator!=(const mint &p) const { return (x >= mod ? x - mod : x) != (p.x >= mod ? p.x - mod : p.x); } u32 get() const { u32 ret = reduce(x); return ret >= mod ? ret - mod : ret; } mint pow(u64 n) const { mint ret(1), mul(*this); while (n > 0) { if (n & 1) ret *= mul; mul *= mul; n >>= 1; } return ret; } mint inverse() const { return pow(mod - 2); } friend ostream &operator<<(ostream &os, const mint &p) { return os << p.get(); } friend istream &operator>>(istream &is, mint &a) { i64 t; is >> t; a = mint(t); return is; } static u32 get_mod() { return mod; } }; using modint = MontgomeryModInt< mod >; std::vector< bool > wildcard_pattern_matching(const string &p, const string &s) { using ll = long long; using usize = std::size_t; using mint = modint; const usize n = p.size(); const usize m = s.size(); assert(n + m - 1 <= (mod - 1 & ~(mod - 1) + 1)); assert(std::all_of(p.begin(), p.end(), [](int x) { return -1 <= x < mod; })); assert(std::all_of(s.begin(), s.end(), [](int x) { return -1 <= x < mod; })); { const int max = std::max(*std::max_element(p.begin(), p.end()), *std::max_element(s.begin(), s.end())); assert(ll(max) *max < mod); assert(ll(max) *max * p.size() < mod); } std::vector< mint > sum(m - n + 1, mint(0)); const auto add = [&](const auto f, const auto g) { std::vector< mint > x(n), y(m); for (usize i = 0; i != n; ++i) { x[i] = f(p[n - 1 - i]); } for (usize i = 0; i != m; ++i) { y[i] = g(s[i]); } const auto z = NumberTheoreticTransformFriendlyModInt< modint >::multiply(x, y); for (usize i = 0; i != m - n + 1; ++i) { sum[i] += z[n - 1 + i]; } }; add([](const int v) { return ll(v != -1) * v * v; }, [](const int v) { return int(v != -1); }); add([](const int v) { return -2 * int(v != -1) * v; }, [](const int v) { return int(v != -1) * v; }); add([](const int v) { return int(v != -1); }, [](const int v) { return ll(v != -1) * v * v; }); std::vector< bool > res(m - n + 1); for (usize i = 0; i != m - n + 1; ++i) { res[i] = sum[i].get() == 0; } return res; } #line 1 "structure/bbst/randomized-binary-search-tree.hpp" template< typename T > class RandomizedBinarySearchTree { using F = function< T(T, T) >; private: struct Node { Node *l, *r; size_t cnt; T key, sum; Node() = default; Node(const T &k) : cnt(1), key(k), sum(k), l(nullptr), r(nullptr) {} }; inline int xor128() { static int x = 123456789; static int y = 362436069; static int z = 521288629; static int w = 88675123; int t; t = x ^ (x << 11); x = y; y = z; z = w; return w = (w ^ (w >> 19)) ^ (t ^ (t >> 8)); } Node *build(int l, int r, const vector< T > &v) { if(l + 1 >= r) return alloc(v[l]); return merge(build(l, (l + r) >> 1, v), build((l + r) >> 1, r, v)); } void dump(Node *t, typename vector< T >::iterator &it) const { if(!t) return; dump(t->l, it); *it = t->key; dump(t->r, ++it); } inline size_t count(const Node *t) const { return t ? t->cnt : 0; } inline T sum(const Node *t) const { return t ? t->sum : e; } inline Node *update(Node *t) { t->cnt = count(t->l) + count(t->r) + 1; t->sum = f(f(sum(t->l), t->key), sum(t->r)); return t; } vector< Node > pool; int ptr; const F f; const T e; public: RandomizedBinarySearchTree(size_t sz, const F &f, const T &e) : pool(sz), f(f), ptr(0), e(e) {} inline Node *alloc(const T &v) { return &(pool[ptr++] = Node(v)); } Node *merge(Node *l, Node *r) { if(!l || !r) return l ? l : r; if(xor128() % (l->cnt + r->cnt) < l->cnt) { l->r = merge(l->r, r); return update(l); } else { r->l = merge(l, r->l); return update(r); } } template< typename... Args > Node *merge(Node *p, Args... args) { return merge(p, merge(args...)); } pair< Node *, Node * > split(Node *t, int k) { if(!t) return {t, t}; if(k <= count(t->l)) { auto s = split(t->l, k); t->l = s.second; return {s.first, update(t)}; } else { auto s = split(t->r, k - count(t->l) - 1); t->r = s.first; return {update(t), s.second}; } } Node *build(const vector< T > &v) { ptr = 0; return build(0, (int) v.size(), v); } vector< T > dump(Node *t) const { vector< T > v(count(t)); auto it = begin(v); dump(t, it); return v; } string to_string(Node *r) { auto s = dump(r); string ret; for(int i = 0; i < s.size(); i++) ret += std::to_string(s[i]) + ", "; return ret; } void insert(Node *&t, int k, const T &v) { auto x = split(t, k); t = merge(merge(x.first, alloc(v)), x.second); } void push_front(Node *&t, const T &v) { t = merge(alloc(v), t); } void push_back(Node *&t, const T &v) { t = merge(t, alloc(v)); } T pop_front(Node *&t) { auto ret = split(t, 1); t = ret.second; return ret.first->key; } T pop_back(Node *&t) { auto ret = split(t, count(t) - 1); t = ret.first; return ret.second->key; } void erase(Node *&t, int k) { auto x = split(t, k); t = merge(x.first, split(x.second, 1).second); } T query(Node *&t, int a, int b) { auto x = split(t, a); auto y = split(x.second, b - a); auto ret = sum(y.first); t = merge(x.first, merge(y.first, y.second)); return ret; } tuple< Node *, Node *, Node * > split3(Node *t, int a, int b) { auto x = split(t, a); auto y = split(x.second, b - a); return make_tuple(x.first, y.first, y.second); } void set_element(Node *&t, int k, const T &x) { if(k < count(t->l)) set_element(t->l, k, x); else if(k == count(t->l)) t->key = t->sum = x; else set_element(t->r, k - count(t->l) - 1, x); t = update(t); } size_t size(Node *t) const { return count(t); } bool empty(Node *t) const { return !t; } }; #line 1 "string/rolling-hash.hpp" /** * @brief Rolling-Hash(ローリングハッシュ) * @see https://qiita.com/keymoon/items/11fac5627672a6d6a9f6 * @docs docs/rolling-hash.md */ struct RollingHash { static const uint64_t mod = (1ull << 61ull) - 1; using uint128_t = __uint128_t; vector< uint64_t > power; const uint64_t base; static inline uint64_t add(uint64_t a, uint64_t b) { if((a += b) >= mod) a -= mod; return a; } static inline uint64_t mul(uint64_t a, uint64_t b) { uint128_t c = (uint128_t) a * b; return add(c >> 61, c & mod); } static inline uint64_t generate_base() { mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count()); uniform_int_distribution< uint64_t > rand(1, RollingHash::mod - 1); return rand(mt); } inline void expand(size_t sz) { if(power.size() < sz + 1) { int pre_sz = (int) power.size(); power.resize(sz + 1); for(int i = pre_sz - 1; i < sz; i++) { power[i + 1] = mul(power[i], base); } } } explicit RollingHash(uint64_t base = generate_base()) : base(base), power{1} {} vector< uint64_t > build(const string &s) const { int sz = s.size(); vector< uint64_t > hashed(sz + 1); for(int i = 0; i < sz; i++) { hashed[i + 1] = add(mul(hashed[i], base), s[i]); } return hashed; } template< typename T > vector< uint64_t > build(const vector< T > &s) const { int sz = s.size(); vector< uint64_t > hashed(sz + 1); for(int i = 0; i < sz; i++) { hashed[i + 1] = add(mul(hashed[i], base), s[i]); } return hashed; } uint64_t query(const vector< uint64_t > &s, int l, int r) { expand(r - l); return add(s[r], mod - mul(s[l], power[r - l])); } uint64_t combine(uint64_t h1, uint64_t h2, size_t h2len) { expand(h2len); return add(mul(h1, power[h2len]), h2); } int lcp(const vector< uint64_t > &a, int l1, int r1, const vector< uint64_t > &b, int l2, int r2) { int len = min(r1 - l1, r2 - l2); int low = 0, high = len + 1; while(high - low > 1) { int mid = (low + high) / 2; if(query(a, l1, l1 + mid) == query(b, l2, l2 + mid)) low = mid; else high = mid; } return low; } }; void beet() { int N, M; cin >> N >> M; string X, Y; cin >> X >> Y; for (auto &p: X) if (p == '?') p = -1; auto Z = wildcard_pattern_matching(Y, X); bool f = false; for(auto z : Z) f |= z; if(!f) { cout << -1 << "\n"; return; } RollingHash rolling_hash; using P = pair< uint64_t, int >; auto F = [&](const P& a, const P& b) { rolling_hash.expand(b.second); return P(RollingHash::add(RollingHash::mul(a.first, rolling_hash.power[b.second]), b.first), a.second + b.second); }; RandomizedBinarySearchTree< P > rbst(N + M + N + M, F, P(0, 0)); vector< P > avs(N), bvs(M); for(int i = 0; i < N; i++) avs[i] = {X[i] == -1 ? 'a' : X[i], 1}; for(int i = 0; i < M; i++) bvs[i] = {Y[i], 1}; auto AT = rbst.build(avs), BT = rbst.build(bvs); auto CT = rbst.build(avs), DT = rbst.build(bvs); int l = -1; for(int i = 0; i < N; i++) { if (Z[i]) { if (l == -1) { l = i; continue; } // [0, i) Y [i + M, ) auto a2 = rbst.split(AT, i + M); auto a1 = rbst.split(a2.first, i); auto ab = rbst.merge(a1.first, BT, a2.second); auto c2 = rbst.split(CT, l + M); auto c1 = rbst.split(c2.first, l); auto cd = rbst.merge(c1.first, DT, c2.second); int len = N; int low = 0, high = len + 1; while (high - low > 1) { int mid = (low + high) / 2; if (rbst.query(ab, 0, mid) == rbst.query(cd, 0, mid)) low = mid; else high = mid; } bool update = false; if (low < N and rbst.query(ab, low, low + 1) < rbst.query(cd, low, low + 1)) { update = true; } auto rev_a1 = rbst.split(ab, i + M); auto rev_a2 = rbst.split(rev_a1.first, i); BT = rev_a2.second; AT = rbst.merge(rev_a2.first, a1.second, rev_a1.second); auto rev_c1 = rbst.split(cd, l + M); auto rev_c2 = rbst.split(rev_c1.first, l); DT = rev_c2.second; CT = rbst.merge(rev_c2.first, c1.second, rev_c1.second); if (update) { l = i; } } } for(int k = 0; k < M; k++) { X[k + l] = Y[k]; } for(auto& x : X) if(x == -1) x = 'a'; cout << X << "\n"; } int main() { int T; cin >> T; while (T--) { beet(); } }