經典問題,但是我為什麼不會呢?????
題意
給定一張 \(n\times m\) 的 01 矩陣,求出有多少個子矩陣使得子矩陣內沒有 1。
\(n,m\le 10^3\)
分析
考慮列舉每一行,計算以該行上每個點為右下角的合法子矩形個數 \(\sum sum_{i,j}\),也就是說,計算左上角的個數使得左上角和該右下角形成的子矩形不包含 1。
其實到這裡已經可以思考單調棧了,但是為了捋順思路,我們還是考慮對於每一行,只有該列上方的第一個 1 會對子矩形大小產生限制,而在某一個 1 往左的比該 1 所在行數要靠前的那些 1 也不會產生限制。據此我們考慮單調棧,預處理 \(up_{i,j}\) 表示 \((i,j)\) 往上第一個 1 和它本身的距離,單調棧裡維護一個遞增的 \(up_{i,j}\) 和 \(\sum sum_{i,j}\),將比 \(up_{i,j}\) 大的點彈完後,令棧頂的列為 \(c\),由於單調棧 \(up\) 遞增,\(sum_{i,c}\) 的答案可以直接繼承到 \(sum_{i,j}\) 中,額外的貢獻還有 \(x\in(up_{i,c},up_{i,j}],y\in (c,j]\) 這部分子矩形的點,把它們加進 \(sum_{i,j}\) 中。
時間複雜度 \(O(nm)\)。
rep(j,1,m){
rep(i,1,n){
if(s[i][j]=='1')up[i][j]=0;
else up[i][j]=up[i-1][j]+1;
}
}
int ans=0;
rep(i,1,n){
tp=0;
sum[0]=0;
rep(j,1,m){
while(tp&&up[i][j]<=up[i][sta[tp]])--tp;
sum[j]=(sum[sta[tp]]+1ll*(j-sta[tp])*up[i][j]%mod)%mod;
ans=(ans+sum[j])%mod;
sta[++tp]=j;
}
}