luogu7715 Shape 题解

枚举极长横杠。

\(f(x,y)\) 为从 \((x,y)\) 最多同时向上向下延伸多少个白色格子。

对于每一行 \(x\),直接处理两个黑色格子中间的部分,设为 \([l,r]\),那么贡献为 \[ \sum_{y_1=l}^r \sum_{y_2=y_1+1}^r \min\{f(x,y_1),f(x,y_2)\} \] 考虑如果将 \(f(x,y)\) 递增排序,那么对于排名为 \(k\)\(f(x,y_0)\) 会贡献出 \(r-k\) 次。

于是乎这部分的复杂度为 \(O(nm \log_2 m)\),可以通过。

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define uint unsigned long long
#define PII pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define pb emplace_back
#define SET(a,b) memset(a,b,sizeof(a))
#define CPY(a,b) memcpy(a,b,sizeof(b))
#define rep(i,j,k) for(int i=(j);i<=(k);++i)
#define per(i,j,k) for(int i=(j);i>=(k);--i)
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
const int N=2005;
int n, m, ans, a[N][N], f[N][N], t[N];
int calc(int i,int l,int r) {
	if(l>r) return 0;
	int cnt=0, res=0;
	rep(j,l,r) t[++cnt]=f[i][j];
	sort(t+1,t+cnt+1);
	rep(j,1,cnt) res+=t[j]*(cnt-j);
	return res;
}
signed main() {
	n=read(), m=read();
	rep(i,1,n) rep(j,1,m) a[i][j]=read();
	rep(j,1,m) {
		int p=-1;
		rep(i,1,n) {
			if(!a[i][j]) ++p; else p=-1;
			f[i][j]=p;
		}
		p=-1;
		per(i,n,1) {
			if(!a[i][j]) ++p; else p=-1;
			f[i][j]=min(f[i][j],p);
		}
	}
	rep(i,1,n) {
		int lst=1;
		rep(j,1,m) if(a[i][j]) ans+=calc(i,lst,j-1), lst=j+1;
		ans+=calc(i,lst,m);
	}
	printf("%lld\n",ans);
}

luogu7715 Shape 题解
https://yozora0908.github.io/2022/lg7715-solution/
作者
yozora0908
发布于
2022年11月12日
许可协议