Description
给出一个 n×m n × m 的矩阵 A A ,每个元素有权值,由矩阵不断复制得到一个无限大矩阵 C C ,求矩阵的一个 p×q p × q 子矩阵 B B 使得矩阵也能生成 C C 矩阵且的代价( B B 中元素点权最大值)最小
Input
第一行两个整数 n,m n , m ,之后输入一个只由小写字母组成的 n×m n × m 矩阵 A A
Output
输出 B B 的代价最小值
Sample Input
2 5
acaca
acaca
3 9 2 8 7
4 5 7 3 1
Sample Output
18
Solution
显然若能生成 C C 矩阵,那么以矩阵为循环节的任一 A A 矩阵的子矩阵均可以生成,这些矩阵元素最大值和 B B 元素最大值相同且行列乘积大于,显然代价比 B B 大,故要选择最小的子矩阵 B B ,由于行列循环相互独立,故只需要求出行之间的最小循环节和列之间的最小循环节即为的值,求行的循环节就把每行元素 hash h a s h 进而得到一个长度为 n n 的序列,用即可得到这个序列的最小循环节,列的循环节同理
在求出 p,q p , q 的值之后,显然 A A 的任意一个子矩阵均可生成 C C ,我们要找的是矩阵最大值最小的子矩阵,首先对每行用优先队列求出以结尾的长度为 q q 的子段的最大值 bi,j b i , j ,再对每行用优先队列求出以 (i,j) ( i , j ) 结尾的长度为 p p 的子段的最大值,这个最大值即为以 (i,j) ( i , j ) 为右下角的 p×q p × q 子矩阵元素最大值,以此更新答案即可
Code
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int INF=0x3f3f3f3f,maxn=1000005;
#define mod 1000000007
char s[maxn];
int n,m,col[maxn],row[maxn],Next[maxn],a[maxn],b[maxn];
P que[maxn];
int ID(int x,int y)
{
return x*m+y;
}
int deal(int *c,int n)
{
for(int i=0,j=-1;i<=n;j++,i++)
{
Next[i]=j;
while(j>-1&&c[i]!=c[j])j=Next[j];
}
return n-Next[n];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%s",s+i*m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&a[ID(i,j)]);
int p,q;
for(int j=0;j<m;j++)
{
col[j]=0;
int temp=1;
for(int i=0;i<n;i++,temp=26ll*temp%mod)
col[j]=(col[j]+(ll)temp*(s[ID(i,j)]-'a')%mod)%mod;
}
for(int i=0;i<n;i++)
{
row[i]=0;
int temp=1;
for(int j=0;j<m;j++,temp=26ll*temp%mod)
row[i]=(row[i]+(ll)temp*(s[ID(i,j)]-'a')%mod)%mod;
}
p=deal(row,n),q=deal(col,m);
for(int i=0;i<n;i++)
{
int st=1,ed=0;
for(int j=0;j<m;j++)
{
while(st<=ed&&j-que[st].second>=q)st++;
while(st<=ed&&a[ID(i,j)]>que[ed].first)ed--;
que[++ed]=P(a[ID(i,j)],j);
if(j>=q-1)b[ID(i,j)]=que[st].first;
}
}
int ans=INF;
for(int j=q-1;j<m;j++)
{
int st=1,ed=0;
for(int i=0;i<n;i++)
{
while(st<=ed&&i-que[st].second>=p)st++;
while(st<=ed&&b[ID(i,j)]>que[ed].first)ed--;
que[++ed]=P(b[ID(i,j)],i);
if(i>=p-1)ans=min(ans,que[st].first);
}
}
printf("%lld\n",(ll)(p+1)*(q+1)*ans);
return 0;
}