题意
有一个n*m的地毯,aij表示地毯每格的元素,bij表示地毯每格的价格,要求选取一块价格最大值最小的地毯,并且这块地毯无限铺开之后,原地毯是其子矩阵。
题解
先找到这个矩阵的最小循环节子矩阵,求一下每行的循环节长度用map记录,取出现次数为m并且循环节长度最小的;每列也求一下循环节长度用map记录,取出现次数为m并且循环节长度最小的;这样就得到了最小的循环节子矩阵。然后问题就变成了求一个p*q的子矩阵最大值的最小值,可以参考这个题 Fake Maxpooling (求得是k*k子矩阵的最大值的和)稍加修改变成求p*q子矩阵的最大值的最小值就好了。这里用到单调队列,先横着算一下每个长度为p的区间的最大值记录下来,然后再把记录下来的数组竖着同样算一下长度为q的区间,将每次求到的最大值取最小值。
ps:谨记像这种横着求一遍竖着求一遍的一定不能求第二遍的时候直接copy第一遍的代码改,会把自己坑死的!!!不要手懒!!!
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+10;
int nt1[maxn];
int nt2[maxn];
string s[maxn];
unordered_map<int,int> mp;
deque<int> dq;
int val[maxn],v[maxn];
void getnt1(string s)
{
int i=0,j=-1;
nt1[0]=-1;
while(i<s.size()){
if(j==-1||s[i]==s[j]) i++,j++,nt1[i]=j;
else j=nt1[j];
}
}
void getnt2(string s)
{
int i=0,j=-1;
nt2[0]=-1;
while(i<s.size()){
if(j==-1||s[i]==s[j]) i++,j++,nt2[i]=j;
else j=nt2[j];
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++) cin>>s[i];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
cin>>v[i*m+j];
}
}
int pp=m,qq=n;
for(int i=0;i<n;i++){
getnt1(s[i]);
int p=nt1[m];
while(p!=-1){
mp[m-p]++;
if(mp[m-p]==n) pp=min(pp,m-p);
p=nt1[p];
}
}
mp.clear();
for(int i=0;i<m;i++){
string t;
for(int j=0;j<n;j++){
t+=s[j][i];
}
getnt2(t);
int p=nt2[n];
while(p!=-1){
mp[n-p]++;
if(mp[n-p]==m) qq=min(qq,n-p);
p=nt2[p];
}
}
int ans=1e9;
for(int i=0;i<n;i++){
while(dq.size()) dq.pop_back();
for(int j=0;j<pp-1;j++){
while(dq.size()&&v[i*m+dq.back()]<=v[i*m+j]) dq.pop_back();
dq.push_back(j);
}
for(int j=pp-1;j<m;j++){
while(dq.size()&&dq.front()+pp<=j) dq.pop_front();
while(dq.size()&&v[i*m+dq.back()]<=v[i*m+j]) dq.pop_back();
dq.push_back(j);
val[i*m+j]=v[i*m+dq.front()];
}
}
for(int i=pp-1;i<m;i++){
while(dq.size()) dq.pop_back();
for(int j=0;j<qq-1;j++){
while(dq.size()&&val[dq.back()*m+i]<=val[j*m+i]) dq.pop_back();
dq.push_back(j);
}
for(int j=qq-1;j<n;j++){
while(dq.size()&&dq.front()+qq<=j) dq.pop_front();
while(dq.size()&&val[dq.back()*m+i]<=val[j*m+i]) dq.pop_back();
dq.push_back(j);
ans=min(ans,val[dq.front()*m+i]);
}
}
ll res=(ll)ans*(ll)(pp+1)*(ll)(qq+1);
cout<<res<<endl;
return 0;
} 
京公网安备 11010502036488号