链接
题解
首先注意到,如果一个子矩阵可以作为循环节,那么如果另一个能作为循环节的矩阵包含了这个矩阵,那么大一点的矩阵的答案一定不会比小矩阵更优。
所以,我只需要找最小循环节。
先把每行求出一个哈希值,然后用这个哈希值做kmp,这样就得到了行方向上的最小循环节长度,假设是p
然后把前p行拿出来,每一列求一个哈希值,再kmp。这样得到一个列方向上的最小循环节
然后现在就相当于拿一个大小为p*q的框,去框一个子矩阵,使得最大值最小
这个东西在两个方向上维护单调队列就可以做
代码
#include <bits/stdc++.h>
#define iinf 0x3f3f3f3f
#define linf (1ll<<60)
#define eps 1e-8
#define maxn 2000010
#define cl(x) memset(x,0,sizeof(x))
#define rep(i,a,b) for(i=a;i<=b;i++)
#define drep(i,a,b) for(i=a;i>=b;i--)
#define em(x) emplace(x)
#define emb(x) emplace_back(x)
#define emf(x) emplace_front(x)
#define fi first
#define se second
#define de(x) cerr<<#x<<" = "<<x<<endl
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
ll n, m;
int Hash[maxn];
struct Array2
{
ll n, m, a[maxn];
void init(ll N, ll M)
{
n=N, m=M;
for(ll i=0;i<n*m;i++)a[i]=0;
}
ll index(ll i, ll j){return i*m+j;}
ll& at(ll i, ll j){return a[index(i,j)];}
ll* operator[](ll i){return a+i*m;}
}w, s, dq;
ll L[maxn], R[maxn];
struct KMP
{
int n, next[maxn], t[maxn];
void build(int *r, int len)
{
int i, j=0;
n=len;
for(i=1;i<=len;i++)t[i]=r[i]; t[len+1]=0;
for(i=2;i<=len;i++)
{
for(;j and t[j+1]!=t[i];j=next[j]);
next[i] = t[j+1]==t[i]?++j:0;
}
}
int move(int pos, int x)
{
for(;pos and t[pos+1]!=x;pos=next[pos]);
return t[pos+1]==x ? pos+1 : 0;
}
}kmp;
char str[maxn], tmp[maxn];
ll gethash(char *s, ll len)
{
ll i, ret=0, base=4894111, mod=998244353;
rep(i,1,len)ret = (ret * base + s[i]) %mod;
return ret;
}
int main()
{
de( ( sizeof(w)+sizeof(s)+sizeof(dq) >>20 ) );
ll i, j;
n=read(), m=read();
w.init(n+1,m+1), s.init(n+1,m+1), dq.init(n+1,m+1);
rep(i,1,n)
{
scanf("%s",str+1);
rep(j,1,m)s[i][j]=str[j];
Hash[i]=gethash(str,m);
}
rep(i,1,n)rep(j,1,m)w[i][j]=read();
kmp.build(Hash,n);
ll p = n - kmp.next[n];
rep(j,1,m)
{
rep(i,1,p)tmp[i]=s[i][j];
Hash[j] = gethash(tmp,p);
}
kmp.build(Hash,m);
ll q = m - kmp.next[m], ans=linf;
rep(j,1,m)
{
rep(i,1,n)
{
auto que = dq[i];
auto &l=L[i], &r=R[i];
if(l<r and que[l]<j-q+1)l++;
while(l<r and w[i][que[r-1]] < w[i][j])r--;
que[r++] = j;
}
deque<int> que;
rep(i,1,n)
{
if(que.size() and que.front()<i-p+1)que.pop_front();
while(que.size() and w[que.back()][ dq[que.back()][L[que.back()]] ] < w[i][ dq[i][L[i]] ])que.pop_back();
que.push_back(i);
if(i>=p and j>=q)
{
ans = min(ans,w[que.front()][ dq[que.front()][L[que.front()]] ]);
}
}
}
printf("%lld",ans*(p+1)*(q+1));
return 0;
}