#单调栈#CodeChef Meteor

METEORAK


分析

\(dp[l][r]\) 表示第 \(l\)\(r\) 行的答案,可以发现它由 \(f[l][r],dp[l][r+1],dp[l+1][r]\) 转移而来。

关键就是求出 \(f[l][r]\),考虑枚举 \(r\),那么实际上组成了一些柱状图,用单调栈维护最大的矩形宽度然后更新一下即可


代码

#include <cstdio>
#include <cctype>
using namespace std;
const int N=1511; bool ban[N][N];
int dp[N][N],n,m,k,h[N],w[N],st[N],Top;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
void Max(int &x,int y){x=x>y?x:y;}
int main(){
	n=iut(),m=iut(),k=iut();
	for (int i=1;i<=k;++i){
		int x=iut(),y=iut();
		ban[x][y]=1;
	}
	for (int i=1;i<=n;++i){
		for (int j=1;j<=m;++j)
		if (ban[i][j]) h[j]=0;
		    else ++h[j];
		Top=0;
		for (int j=1;j<=m+1;++j){
			int width=0;
			while (Top&&h[st[Top]]>=h[j]){
				width+=w[Top];
				Max(dp[i-h[st[Top]]+1][i],width);
				--Top;
			}
			st[++Top]=j,w[Top]=width+1;
		}
		for (int j=1;j<i;++j) Max(dp[j+1][i],dp[j][i]);
		for (int j=1;j<=i;++j) dp[j][i]*=i-j+1;
	}
	for (int len=1;len<n;++len)
	for (int i=1;i+len<=n;++i)
	    Max(dp[i][i+len],dp[i][i+len-1]),
	        Max(dp[i][i+len],dp[i+1][i+len]);
	for (int Q=iut();Q;--Q){
		int l=iut(),r=iut();
		print(dp[l][r]),putchar(10);
	}
	return 0;
}
posted @ 2022-03-15 07:23  lemondinosaur  阅读(22)  评论(0编辑  收藏  举报