首页 > 其他分享 >悬线法

悬线法

时间:2024-07-09 23:31:21浏览次数:7  
标签:const 悬线法 int long -- ans define

使用 \(dp\) \(O(n*m)\) 解决矩阵最大面积问题。

两种解法,一种直接抄板子,但是需要将图抽象成为二维平面上,一些点固定可选,一些点固定不可选。换句话说,对于一个 \(01\) 矩阵,找出一个面积最大的矩形使得这个矩形内所有点都是 \(1\) 。

另一种解法,悬线找出每个节点可以向上/下扩展的最大长度,然后问题就转化成为了求解一个区间长度乘以区间最小值的最大值这题

题目1

解法一:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define endl '\n'
const int N=2e3+5;
const int mod=998244353;
short A[N*2][N],l[N*2][N],r[N*2][N],u[N*2][N];
void solve()
{
    int n,m;cin>>n>>m;
    memset(A,0,sizeof A);
    memset(l,0,sizeof l);
    memset(r,0,sizeof r);
    memset(u,0,sizeof u);

    //图转化
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>A[(i-1)*2+1][j];
    n=n*2;
    for(int j=1;j<=m;j++)
    {
        for(int i=1;i<=n;i+=2)
        {
            if(A[i][j]>A[i+2][j]) A[i+1][j]=0;
            else A[i+1][j]=1;
        }
    }

    //固定板子
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j])
                l[i][j]=l[i][j-1]+1;

    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            if(A[i][j])
                r[i][j]=r[i][j+1]+1;

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j]) 
            {
                u[i][j]=u[i-1][j]+1;
                if(A[i-1][j]) l[i][j]=min(l[i][j],l[i-1][j]),r[i][j]=min(r[i][j],r[i-1][j]);
                ans=max(ans, (int)(r[i][j]+l[i][j]-1)*(int)(u[i][j]+1)/2 );
            }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

解法二:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=2e3+5;
const int mod=998244353;
int a[N][N],b[N][N];
void solve()
{
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin>>a[i][j];
    for(int j=1;j<=m;j++)
    {
        int ls=1;
        for(int i=1;i<=n;i++)
        {
            if(a[i-1][j]>a[i][j]) 
            {
                for(int l=i-1;l>=ls;l--) b[l][j]=(i-1)-l+1;
                ls=i;
            }
        }
        for(int l=n;l>=ls;l--) b[l][j]=n-l+1;
    }
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        stack<pii>s;
        s.push({0,0});
        for(int j=1;j<=m;j++)
        {
            while(s.top().first>=b[i][j])
            {  
                int w=s.top().first;
                s.pop();                
                ans=max(ans,(j-s.top().second-1)*w);
            }
            s.push({b[i][j],j});
        }
        while(s.size()!=1)
        {
            int w=s.top().first;
            s.pop();        
            ans=max(ans,(m-s.top().second)*w);
        }
    }
    cout<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T;cin>>T;
    while(T--) solve();
    return 0;
}

题目2

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define db double
#define il inline
#define x first
#define y second
#define endl '\n'
const int N=4e3+5;
const int mod=998244353;
short a[N][N],A[N][N],l[N][N],r[N][N],u[N][N];
void solve()
{
    int n,m;cin>>n>>m;
    n*=2,m*=2;
    for(int i=1;i<=n;i+=2)
        for(int j=1;j<=m;j+=2)
            cin>>a[i][j];
    
    //图转化
    for(int i=1;i<=n;i+=2)
        for(int j=1;j<=m;j+=2)
        {
            A[i][j]=1;
            if(a[i][j]!=a[i+2][j]) A[i+1][j]=1;
            if(a[i][j]!=a[i][j+2]) A[i][j+1]=1;
        }

    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(i%2==0&&j%2==0) A[i][j]=1;
    
    //板子
    int ans=0,ans1=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(A[i][j])
                l[i][j]=l[i][j-1]+1;

    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            if(A[i][j])
                r[i][j]=r[i][j+1]+1;

    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            if(A[i][j]) 
            {
                u[i][j]=u[i-1][j]+1;
                if(A[i-1][j]) l[i][j]=min(l[i][j],l[i-1][j]),r[i][j]=min(r[i][j],r[i-1][j]);
                ans=max(ans, (r[i][j]+l[i][j])/2*((u[i][j]+1)/2) );
                ans1=max(ans1,min((r[i][j]+l[i][j])/2,((u[i][j]+1)/2))*min((r[i][j]+l[i][j])/2,((u[i][j]+1)/2)));
            }
        }
    }
    cout<<ans1<<endl<<ans<<endl;
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int T=1;//cin>>T;
    while(T--) solve();
    return 0;
}

标签:const,悬线法,int,long,--,ans,define
From: https://www.cnblogs.com/mhw-mathcode/p/18292944

相关文章

  • 动态规划——悬线法
    动态规划——悬线法P4147玉蟾宫1//动态规划——悬线法2#include<iostream>3#include<cmath>4usingnamespacestd;5constintN=1010;6intn,m;7chara[N][N];8inth[N][N];//保存高度9intl[N][N],r[N][N];10intmain(){11cin>>n>>m;......
  • 5.8 单调栈 & 悬线法 & 相关的题(和 dp 也多少沾点)
    今日小题:一个CFdiv2的A的签到题,记录一下这个做法:求一个字符串的最长非回文字符串:无解:长度为1或整个串每个字符都一样;有解:判断这个串是不是回文,如果不是,输出长度,如果是输出长度-1。感觉非常妙。不写证明,感觉非常好想...#include<bits/stdc++.h>usingnamespacestd;i......
  • 悬线法学习笔记
    悬线法学习笔记单调栈可以解决的问题,一部分可以用悬线法解决,悬线法更容易理解,代码量差不多。SPOJ.com-ProblemHISTOGRA找元素的左右扩展区间。如果用选线法处理的话,......