Largest Common Submatrix(每日dp(划)每日一题)

给两个矩阵,其中数字由1到n*m,求两个矩阵的公共最大矩阵。。。
啊啊啊啊我好菜

#include<bits/stdc++.h>

using namespace std;
char str[1005];
int dp[1005][1005];
int a[1005][1005];
int b[1006][1006];
int sum[1006][1006];
int len[1006][1006];
struct MP
{
    int x,y;
}mp[1005*1005];


int UP[1006],DOWN[1006];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            mp[a[i][j]]={i,j};
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&b[i][j]);
            
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=1;j<=m;j++){
            sum[i][j]=1;
            MP pre=mp[b[i][j-1]];
            MP now=mp[b[i][j]];
            if(pre.x==now.x&&pre.y==now.y-1){
                sum[i][j]+=sum[i][j-1];
            }
            len[i][j]=1;
            MP up=mp[b[i+1][j]];
            if(up.x==now.x+1&&up.y==now.y){
                len[i][j]+=len[i+1][j];
            }
        }
    }
   
    int ans=0;
    for(int i=1;i<=m;i++){
        stack<int> s;
        int j=1;
        while(j<=n){
            int ed=j+len[j][i];
            for(;j<ed;j++){
                if(s.size()==0||sum[s.top()][i]<=sum[j][i]){
                    s.push(j);
                }else {
                    int top;
                    while(s.size()&&sum[s.top()][i]>sum[j][i]){
                        top=s.top();
                        int res=j-s.top();
                        ans=max(ans,res*sum[s.top()][i]);
                        s.pop();
                    }
                    s.push(top);
                    sum[top][i]=sum[j][i];
                }
            }
            while(s.size()){
                int res=ed-s.top();
                ans=max(res*sum[s.top()][i],ans);
                s.pop();
            }
            j=ed;
        } while(s.size()){
                int res=n-s.top()+1;
                ans=max(res*sum[s.top()][i],ans);
                s.pop();
            }
        
    }printf("%d",ans);
}

求最大矩阵是有两种方法,然鹅另外一种卡的莫名其妙,就学了现在这种,以后用这种单调栈求法吧,好菜啊啊啊啊。。。

upd;原来的方法是下标写错了。。。啊啊啊啊浪费了一个上午。。。

#include<bits/stdc++.h>

using namespace std;
char str[1005];
int dp[1005][1005];
int a[1005][1005];
int b[1006][1006];
int sum[1006][1006];
int len[1006][1006];
struct MP
{
    int x,y;
}mp[1005*1005];


int UP[1006],DOWN[1006];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            mp[a[i][j]]={i,j};
        }
    }

    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&b[i][j]);
            sum[i][j]=1;
            MP pre=mp[b[i][j-1]];
            MP now=mp[b[i][j]];
            if(pre.x==now.x&&pre.y==now.y-1){
                sum[i][j]+=sum[i][j-1];
            }
            len[i][j]=1;
            MP up=mp[b[i-1][j]];
            if(up.x+1==now.x&&up.y==now.y){
                len[i][j]+=len[i-1][j];
            }
        }
    }
   
    int ans=0;
    for(int i=m;i>=1;i--){
        stack<int> s;
        sum[0][i]=0x3f3f3f3f;
        s.push(0);
        for(int j=1;j<=n;j++){//上向下
            int now=j,down=j-1;
            if(len[now][i]-1==len[down][i]){
                while(s.size()>1&&sum[s.top()][i]>=sum[j][i])s.pop();
            }else {
                while(s.size())s.pop();s.push(j-1);
            }
            UP[j]=s.top(); 
            s.push(j);
        }
        while(s.size())s.pop();
        sum[n+1][i]=0x3f3f3f3f;
        s.push(n+1);
        int tim=0;
        for(int j=n;j>=1;j--){//从下向上
            int now=j,down=j+1;
            if(len[now][i]==len[down][i]-1){
                while(s.size()>1&&sum[s.top()][i]>=sum[j][i]){
                    s.pop();
                }
            }else {
                while(s.size())s.pop();s.push(j+1);
            }
            DOWN[j]=s.top();
            s.push(j);
        }
        for(int j=1;j<=n;j++){
            ans=max(sum[j][i]*(DOWN[j]-UP[j]-1),ans);
        }
    }printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值