题意

让你求一个子矩阵,这个子矩阵无限拓展之后,可以让原来的矩阵变成这个无限矩阵的子矩阵,并且要使得cost最小, cost是这个子矩阵的最大值 * (子矩阵宽 + 1) * (子矩阵高 + 1)

思路

很显然,我们要求的矩阵尽量小,因为横向和纵向不相互影响, 那么我们可以横向纵向求最小周期,这样就可以保证矩阵最小

求完最小矩阵的长宽后,我们就要求这个矩阵位于哪里,可以使得矩阵里面的最大值最小,这个就可以出动我们的单调队列的,首先,维护一个单调递减的队列,这样队首就是最大值,然后的话,还得主要超过(宽或者高的)我们就抛弃掉了

代码

/**
 *    author: andif
 *    created: 23.06.2023 01:13:28
**/
#include<bits/stdc++.h>
using namespace std;

#define de(x) cerr << #x << " = " << x << endl
#define dd(x) cerr << #x << " = " << x << " "
#define rep(i, a, b) for(int i = a; i < b; ++i)
#define per(i, a, b) for(int i = a; i > b; --i)
#define mt(a, b) memset(a, b, sizeof(a))
#define sz(a) (int)a.size()
#define fi first
#define se second
#define qc ios_base::sync_with_stdio(0);cin.tie(0)
#define eb emplace_back
#define all(a) a.begin(), a.end()
using ll = long long;
using db = double;
using pii = pair<int, int>;
using pdd = pair<db, db>;
using pll = pair<ll, ll>;
using vi = vector<int>;
const db eps = 1e-9;

vi get_next(const string& s) {
    int n = sz(s) - 1;
    vi next(n + 1, 0);
    rep(i, 2, n + 1) {
        int j = i - 1;
        while(j && s[i] != s[next[j] + 1]) j = next[j];
        if (j) next[i] = next[j] + 1;
    }
    return next;
}

int gao(const vector<string>& s) {
    int n = sz(s[1]) - 1;
    int ret = n;
    vi cnt(n + 1);
    rep(i, 1, sz(s)) {
        const string& si = s[i];
        vi next = get_next(si);
        int j = n;
        while(j) {
            cnt[n - next[j]]++;
            j = next[j];
        }
    }
    rep(i, 1, n + 1) {
        // dd(i), de(cnt[i]);
        if (cnt[i] == sz(s) - 1) {
            ret = i;
            break;
        }
    }
    return ret;
}

int main() {
    qc;
    int n, m; cin >> n >> m;
    vector<string> s(n + 1);
    rep(i, 1, n + 1) {
        cin >> s[i];
        s[i] = '#' + s[i];
        // dd(i), de(s[i]);
    }
    vector<string> t(m + 1);
    rep(i, 1, m + 1) {
        string tmp = "#";
        rep(j, 1, n + 1) {
            tmp += s[j][i];
        }
        t[i] = move(tmp);
        // dd(i), de(t[i]);
    }
    vector<vi> a(n + 1, vi(m + 1, 0));
    rep(i, 1, n + 1) rep(j, 1, m + 1) cin >> a[i][j];

    // auto check = [&] (int x, int p, int q) {
    //     vector<vi> b(n + 1, vi(m + 1, 0));
    //     rep(i, 1, n + 1) rep(j, 1, m + 1) {
    //         b[i][j] = a[i][j] > x ? 1 : 0;
    //     }
    //     rep(i, 1, n + 1) rep(j, 1, m + 1) b[i][j] += b[i][j - 1];
    //     rep(j, 1, m + 1) rep(i, 1, n + 1) b[i][j] += b[i - 1][j];
    //     rep(i, 1, n + 1) rep(j, 1, m + 1) {
    //         int ni = i + q - 1, nj = j + p - 1;
    //         if (ni > n || nj > m) continue;
    //         int value = b[ni][nj] - b[ni][j - 1] - b[i - 1][nj] + b[i - 1][j - 1];
    //         if (!value) return true;
    //     }
    //     return false;
    // };

    int p = gao(s), q = gao(t);
    // dd(p), de(q);
    // int l = 0, r = 1e9;
    // while(l + 1 < r) {
    //     int mid = (l + r) >> 1;
    //     if (check(mid, p, q)) {
    //         r = mid;
    //     } else {
    //         l = mid;
    //     }
    // }
    // ll ans = check(l, p, q) ? l : r;
    ll ans = 1e9;
    deque<int> dq;
    auto b = a;
    rep(i, 1, n + 1) {
        while(sz(dq)) dq.pop_back();
        rep(j, 1, m + 1) {
            while(sz(dq) && j - dq.front() + 1 > p) dq.pop_front();
            while(sz(dq) && a[i][dq.back()] <= a[i][j]) dq.pop_back();
            dq.push_back(j);
            b[i][j] = a[i][dq.front()];
        }
    }

    rep(j, 1, m + 1) {
        while(sz(dq)) dq.pop_back();
        rep(i, 1, n + 1) {
            while(sz(dq) && i - dq.front() + 1 > q) dq.pop_front();
            while(sz(dq) && b[dq.back()][j] <= b[i][j]) dq.pop_back();
            dq.push_back(i);
            if (i >= q && j >= p)
                ans = min(ans, 1ll * b[dq.front()][j]);
        }
    }
    ans = ans * (p + 1) * (q + 1);
    cout << ans << '\n';
    return 0;
}