首页 > 其他分享 >ABC311G One More Grid Task 题解

ABC311G One More Grid Task 题解

时间:2023-12-16 19:33:07浏览次数:25  
标签:Task int 题解 long stl rg fo ABC311G define

给出 \(n\times m\) 的矩阵 \(a\)。求权值最大子矩形的权值。

一个矩形的权值定义为它里面全部数的和乘上最小值。

\(n,m\leq 300,0\leq a_{i,j}\leq 300\)。

枚举最小的数 \(a_{i,j}\)。则在满足 \(a_{i,j}\) 是最小值时,包含 \((i,j)\) 的矩形一定是极大的。

这些矩形不好枚举,也难以计算究竟有多少个。

考虑添加一些限制。

枚举上下边界。那么我们枚举列,以这一列的最小值为待定矩形的最小值,然后向左右拓展为一个极大的矩形。

发现这样拓展出的矩形与上面做法的矩形形成双射。

拓展可以采用二维 ST 表+二分实现。时间复杂度 \(O(n^3\log{n})\)。

哦还可以单调栈。时间是 \(O(n^3)\)。

单调栈:

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define rg register
#define ld long double
#define ull unsigned long long
#define gc getchar
#define pc putchar
#define pob pop_back
#define ump unordered_map
#define vi vector<int>
#define vl vector<ll>
#define fo(i,l,r) for(rg int i=(l);i<=(r);++i)
using namespace std;
inline int re() {
	rg int x=0,p=0;rg char c=getchar();
	while(c<'0'||c>'9') (!p)?(p=c=='-'):(p=p),c=getchar();
	while('0'<=c&&c<='9') (x*=10)+=c-48,c=getchar();
	if(p) x=-x;
	return x;
}
inline ll rel() {
	rg ll x=0;rg int p=0;rg char c=getchar();
	while(c<'0'||c>'9') (!p)?(p=c=='-'):(p=p),c=getchar();
	while('0'<=c&&c<='9') (x*=10)+=c-48,c=getchar();
	if(p) x=-x;
	return x;
}
inline void wt(rg int x) { if(x<0) pc('-'),x=-x;if(x>9) wt(x/10);pc(x%10+48); }
inline void wtl(rg ll x) { if(x<0) pc('-'),x=-x;if(x>9) wtl(x/10);pc(x%10+48); }

const int N=305;
const int Lg=9;
int n,m,a[N][N],s[N][N],ql[N],qr[N],mn[N],stl;
struct pr { int v,i; }sta[N];
ll ans;
inline int Sum(rg int l1,rg int r1,rg int l2,rg int r2) {
	return s[l2][r2]-s[l1-1][r2]-s[l2][r1-1]+s[l1-1][r1-1];
}
int main() {
//	freopen(".in","r",stdin),freopen(".out","w",stdout);
	n=re(),m=re();
	fo(i,1,n) {
		fo(j,1,m) {
			a[i][j]=re();
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
		}
	}
	fo(x,1,n) {
		fo(i,1,m) mn[i]=1000;
		fo(y,x,n) {
			fo(i,1,m) mn[i]=min(mn[i],a[y][i]);
			stl=0;
			fo(i,1,m) {
				while(stl&&sta[stl].v>=mn[i]) stl--;
				if(stl) ql[i]=sta[stl].i+1;
				else ql[i]=1;
				sta[++stl]={mn[i],i};
			}
			stl=0;
			for(rg int i=m;i>=1;--i) {
				while(stl&&sta[stl].v>=mn[i]) stl--;
				if(stl) qr[i]=sta[stl].i-1;
				else qr[i]=m;
				sta[++stl]={mn[i],i};
			}
			fo(i,1,m) {
				ans=max(ans,1ll*mn[i]*Sum(x,ql[i],y,qr[i]));
			}
		}
	}
	wtl(ans);
}

ST 表:

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define rg register
#define ld long double
#define ull unsigned long long
#define gc getchar
#define pc putchar
#define pob pop_back
#define ump unordered_map
#define vi vector<int>
#define vl vector<ll>
#define fo(i,l,r) for(rg int i=(l);i<=(r);++i)
using namespace std;
inline int re() {
	rg int x=0,p=0;rg char c=getchar();
	while(c<'0'||c>'9') (!p)?(p=c=='-'):(p=p),c=getchar();
	while('0'<=c&&c<='9') (x*=10)+=c-48,c=getchar();
	if(p) x=-x;
	return x;
}
inline ll rel() {
	rg ll x=0;rg int p=0;rg char c=getchar();
	while(c<'0'||c>'9') (!p)?(p=c=='-'):(p=p),c=getchar();
	while('0'<=c&&c<='9') (x*=10)+=c-48,c=getchar();
	if(p) x=-x;
	return x;
}
inline void wt(rg int x) { if(x<0) pc('-'),x=-x;if(x>9) wt(x/10);pc(x%10+48); }
inline void wtl(rg ll x) { if(x<0) pc('-'),x=-x;if(x>9) wtl(x/10);pc(x%10+48); }

const int N=305;
const int Lg=9;
int n,m,st[N][N][Lg][Lg],g[N],c[N],s[N][N];
ll ans;
int query(int l1,int r1,int l2,int r2) {
	int sl=g[l2-l1+1],sr=g[r2-r1+1];
//	printf("%d %d %d %d = %d\n",l1,r1,l2,r2,min({st[l1][r1][sl][sr],st[l1][r2-(1<<sr)+1][sl][sr],st[l2-(1<<sl)+1][r1][sl][sr],st[l2-(1<<sl)+1][r2-(1<<sr)+1][sl][sr]}));
	return min({st[l1][r1][sl][sr],st[l1][r2-(1<<sr)+1][sl][sr],st[l2-(1<<sl)+1][r1][sl][sr],st[l2-(1<<sl)+1][r2-(1<<sr)+1][sl][sr]});
}
int Sum(int l1,int r1,int l2,int r2) {
	return s[l2][r2]-s[l1-1][r2]-s[l2][r1-1]+s[l1-1][r1-1];
}
int main() {
//	freopen(".in","r",stdin),freopen(".out","w",stdout);
	fo(i,2,300) g[i]=g[i/2]+1;
	n=re(),m=re();
	fo(i,1,n) {
		fo(j,1,m) {
			st[i][j][0][0]=re();
			s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+st[i][j][0][0];
		}
	}
	fo(x,0,g[n]) {
		fo(y,0,g[m]) {
			if(!x&&!y) continue;
			for(int i=1;i+(1<<x)-1<=n;i++) {
				for(int j=1;j+(1<<y)-1<=m;j++) {
					if(!x) st[i][j][x][y]=min(st[i][j][x][y-1],st[i][j+(1<<y-1)][x][y-1]);
					else if(!y) st[i][j][x][y]=min(st[i][j][x-1][y],st[i+(1<<x-1)][j][x-1][y]);
					else st[i][j][x][y]=min({st[i][j][x-1][y-1],st[i][j+(1<<y-1)][x-1][y-1],st[i+(1<<x-1)][j][x-1][y-1],st[i+(1<<x-1)][j+(1<<y-1)][x-1][y-1]});
				}
			}
		}
	}
	fo(x,1,n) {
		fo(y,x,n) {
			fo(i,1,m) {
				int p=query(x,i,y,i),ql,qr;
				int L=1,R=i;
				while(L<=R) {
					int mid=L+R>>1;
					if(query(x,mid,y,i)==p) R=(ql=mid)-1;
					else L=mid+1;
				}
				L=i,R=m;
				while(L<=R) {
					int mid=L+R>>1;
					if(query(x,i,y,mid)==p) L=(qr=mid)+1;
					else R=mid-1;
				}
				ans=max(ans,1ll*p*Sum(x,ql,y,qr));
			}
		}
	}
	wtl(ans);
}

标签:Task,int,题解,long,stl,rg,fo,ABC311G,define
From: https://www.cnblogs.com/2008verser/p/17905214.html

相关文章

  • SP21690 POWERUP - Power the Power Up 题解
    题目传送门前置知识扩展欧拉定理解法直接对\(a\)和\(b^c\)分讨,跑一遍扩展欧拉定理就行了。另外由于本题的特殊规定\(0^0=1\),故需要在当\(a=0\)时,对\(b^c\)进行判断。手模几组样例,发现结论挺显然的。代码#include<bits/stdc++.h>usingnamespacestd;#definell......
  • SP10050 POWTOW - Power Tower City 题解
    题目传送门前置知识扩展欧拉定理解法本题幂塔是有限层的,这里与luoguP4139上帝与集合的正确用法中的无限层幂塔不同,故需要在到达递归边界\(n+1\)时进行特殊处理,对于处理\(\varphi(p)\)在递归过程中等于\(1\)的情况两题基本一致。回忆扩展欧拉定理中的\(b\)和\(\v......
  • P1405 苦恼的小明 题解
    题目传送门前置知识扩展欧拉定理解法本题幂塔是有限层的,这里与luoguP4139上帝与集合的正确用法中的无限层幂塔不同,故需要在到达递归边界时进行特殊处理,对于处理\(varphi(p)\)在递归过程中等于\(1\)的情况两题基本一致。回忆扩展欧拉定理中的\(b\)和\(\varphi(p)\)......
  • CF1804F Approximate Diameter 题解
    题目链接点击打开链接题目解法很有意思的题,但不难首先一个显然的结论是:算着边的加入,直径长度递减第一眼看到误差范围是2倍,可以想到二分可以观察到如果取答案为\(\frac{n}{2}\)可以覆盖到\(\frac{n}{4}\)(上下取整不重要),那这样每次可以把值域范围缩小4倍,然后只要二分直......
  • [ARC124C] LCM of GCDs 题解
    题目跳转Fake_Solution前言[warning]:本题解的做法是错法,但是正确概率贼高。离谱的是正确率还可以叠加。正解是记搜,时间复杂度可以证明。正解看文末。思考众所周知一个公式:\[a\timesb=\operatorname{lcm}(a,b)\times\gcd(a,b)\]如果你不知道——自证吧,不难。于是,移一......
  • CF327C Magic Five 题解
    题目传送门前置知识等比数列求和公式|乘法逆元解法设\(lena\)表示\(a\)的长度。首先,若一个数能被\(5\)整除,则该数的末尾一定为\(0\)或\(5\)。故考虑枚举\(a\)中所有的\(0\)和\(5\)的下标,设此下标后面有\(x\)个数字,由于\(s\)是由\(a\)复制\(k\)遍形......
  • gamble 题解报告
    #Galble题解简要题意:  给定一个数$n$AB两人赌博,每次你作为第三者下注任意整数$x$元,A赢则获得$x$元,否则亏损$x$元。任何一个人赢$n$次立刻结束游戏。你需要每次基于现在的情况,计算下的赌注,以使得在整个赌博的全过程,如果A胜利则获得$2^{2n-1}$元,否则亏损这么......
  • 题解 CF1887E【Good Colorings】
    萌萌交互题。对网格图进行二分图建模,左部\(n\)个点表示每一行,右部\(n\)个点表示每一列。若格子\((i,j)\)被染成\(c\)色,就连接\((L_i,R_j,c)\)的边。由抽屉原理易证,在初始局面中至少有一个各边颜色均不同的偶环。获胜条件相当于存在一个各边颜色均不同的四元环。讨论......
  • 洛谷P1824 进击的奶牛 题解 二分答案
    题目链接:https://www.luogu.com.cn/problem/P1824题目大意:本题相当于在\(n\)个数中选\(c\)个数,使得这\(c\)个数中相差最小的两个数之差尽可能地大。解题思路:我们首先可以给\(a_1\sima_n\)从小到大排一下序(这里有点贪心的思想,你会发现很多涉及贪心的问题在排序之后解......
  • ABC332G Not Too Many Balls 题解
    第\(i\)种球有\(a_i\)个,共\(n\)种。第\(i\)种箱子最多共装\(b_i\)个球。共\(m\)种。第\(i\)种球在第\(j\)种箱子里至多放\(ij\)个。问所有箱子放的球数最多是多少。\(1\leqn\leq500,1\leqm\leq5e5,0\leqa_i,b_i\leq1e12\)。很容易建出网络流模型。......