zoukankan      html  css  js  c++  java
  • CF407D Largest Submatrix 3 题解

    Codeforces
    Luogu

    Description.

    给定一个 \(n\times m\) 的矩阵,求最大的子矩阵,满足其没有重复元素。
    \(n\le 400\)

    Solution1.

    复杂度 \(O(n^3\log n)\)无法通过

    考虑枚举矩阵上边界和下边界。
    对于每个点维护如果它作为右边界所能到达的最左边界。
    然后,每次下边界下移,我们发现会更新一些点的信息。
    就是如果新加入的一行中一个元素在过去出现过,我们就需要跟新它。
    然后直接用一个 set 维护,每次查询前驱后继。

    Solution2.

    考虑在 Solution1 的基础上优化。
    考虑更换枚举方向,上边界从下往上移动,下边界从上往下移动。
    维护的东西和 Solution1 相同,下边界下移,可以利用上一次求出的信息。
    上边界上移,从删数变成了加数,删数的话必须重新处理,加数就可以利用之前的性质了。
    然后相当于每次多出来了最上面一行,根本不需要用 set

    Coding.

    点击查看 Solution1 代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int N=405;int n,m,a[N][N],L[N][N];set<int>st[N*N];
    inline void ckmx(int &a,int b) {a>b?a:a=b;}
    int main()
    {
    	read(n,m);for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
    	int rs=0;for(int up=1;up<=n;up++)
    	{
    		for(int dw=up-1;dw<=n;dw++) for(int r=1;r<=m;r++) L[dw][r]=1;
    		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++)
    		{
    			int vl=a[dw][r];ckmx(L[dw][r],max(L[dw][r-1],L[dw-1][r]));
    			if(!st[vl].empty()&&*st[vl].begin()<=r) ckmx(L[dw][r],*--st[vl].upper_bound(r)+1);
    			if(!st[vl].empty()&&*st[vl].rbegin()>=r) ckmx(L[dw][*st[vl].lower_bound(r)],r+1);
    			st[a[dw][r]].insert(r);
    		}
    		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) rs=max(rs,(r-L[dw][r]+1)*(dw-up+1));
    		//for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) printf("%d%c",(r-L[dw][r]+1)*(dw-up+1),r==m?'\n':' ');
    		//for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) printf("%d%c",L[i][j],j==m?'\n':' ');
    		for(int dw=up;dw<=n;dw++) for(int r=1;r<=m;r++) st[a[dw][r]].clear();
    	}
    	return printf("%d\n",rs),0;
    }
    
    点击查看 Solution2 代码
    //是啊,你就是那只鬼了,所以被你碰到以后,就轮到我变成鬼了{{{
    #include<bits/stdc++.h>
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
    	x=0;char c=getchar(),f=0;
    	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
    	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    	f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int N=405;int n,m,a[N][N],L[N][N],ls[N][N],tn[N*N];
    inline void ckmx(int &a,int b) {a>b?a:a=b;}
    int main()
    {
    	read(n,m);for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
    	int rs=0;for(int up=n;up>=1;up--)
    	{
    		for(int l=1;l<=m;l++)
    			ls[up][l]=max(ls[up][l-1],tn[a[up][l]]+1),
    			tn[a[up][l]]=l,rs=max(rs,l-ls[up][l]+1);
    		for(int l=1;l<=m;l++) tn[a[up][l]]=0;
    		for(int dw=up+1;dw<=n;dw++)
    		{
    			for(int l=1;l<=m;l++)
    			{
    				ls[dw][l]=a[up][l]^a[dw][l]?max(ls[dw][l],max(tn[a[up][l]],tn[a[dw][l]])+1):l+1;
    				ckmx(ls[dw][l],max(ls[dw-1][l],ls[dw][l-1])),tn[a[up][l]]=tn[a[dw][l]]=l;
    				rs=max(rs,(dw-up+1)*(l-ls[dw][l]+1));
    			}
    			for(int l=1;l<=m;l++) tn[a[up][l]]=tn[a[dw][l]]=0;
    		}
    	}
    	return printf("%d\n",rs),0;
    }
    
  • 相关阅读:
    《Fluent Python》 CH.06_函数_使用一等函数实现设计模式 (函数式策略模式+命令模式)
    《Python+Spark 2.0+Hadoop》第10章 Python Spark RDD 读书笔记 (转换/动作运算、广播变量、累加器、示例略)
    《Fluent Python》 CH.05_数据结构-一等函数 (函数对象的各种内置函数、operator模块、itemgetter 和 attrgetter迭代/取值函数)
    JAVA时间字符串去空格、冒号和横杠
    Maven 构建生命周期(compile与install的区别)
    MySQL-进程占用CPU资源高问题分析
    K8S-二进制安装部署高可用集群环境
    Oracle-DG环境中Gap
    MySQL-主从复制环境升级小版本软件
    SequoiaDB
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15194064.html
Copyright © 2011-2022 走看看