CF 373D Counting Rectangles is Fun 单调栈+DP

来源:互联网 发布:java多线程抢票代码 编辑:程序博客网 时间:2024/05/21 21:56
题意:n*m的01矩阵,q次询问,每次询问左上角为(a,b),右下角为(c,d)的矩形中 有多少个全0的子矩形?
n,m<=40,q<=3e5.


n,m<=40 大胆的设状态 dp[a][b][c][d] 左上为(a,b)右下为(c,d)中有多少个全0子矩形.
类似二维前缀和 dp[a][b][c][d]=dp[a][b][c-1][d]+dp[a][b][c][d-1]-dp[a][b][c-1][d-1]+fun(a,b,c,d)
calc计算(c,d)为右下角,左上不超出(a,b)时,有多少个全0子矩形 总共O(n^6).


calc这部分暴力计算为O(n^2) 根据单调栈的经典应用:(c,d)为右下时,元素都相同的子矩形个数.
因为如果h[c][d]>h[c][d-1],则cnt[i][j]=cnt[i][j-1]+h[i][j]
根据右下(c,d)的宽度来分类计算,用单调栈来维护(c,d)前面第一个高度小于h[c][d]的位置k,中间部分个数为(d-k)*h[c][d]. 本题注意不超过左上边界即可.

时间复杂度O(n^4),

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=45;int n,m,q,g[N][N],dp[N][N][N][N];int h[N][N],cnt[N][N][N][N],s[N];char t[N];void solve(){for(int a=1;a<=n;a++){for(int b=1;b<=m;b++){for(int c=a;c<=n;c++){int top=0;for(int d=b;d<=m;d++){if(g[c][d])top=0,cnt[a][b][c][d]=0,s[++top]=d;else{while(top&&h[c][d]<=h[c][s[top]])top--;int k=s[top];cnt[a][b][c][d]=cnt[a][b][c][k]+min((d-k),(d-b+1))*min(h[c][d],(c-a+1));////printf("%d %d %d %d %d\n",a,b,c,d,cnt[a][b][c][d]);s[++top]=d;}dp[a][b][c][d]=dp[a][b][c-1][d]+dp[a][b][c][d-1]-dp[a][b][c-1][d-1]+cnt[a][b][c][d];}}}}}int main(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++){scanf("%s",t+1);for(int j=1;j<=m;j++){g[i][j]=t[j]-'0';if(g[i][j])h[i][j]=0;elseh[i][j]=h[i-1][j]+1;}}solve();while(q--){int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);printf("%d\n",dp[a][b][c][d]);}return 0;}


这题O(n^5)也能通过,写起来简单点.还有一种是2维前缀和 然后又4维前缀和...什么鬼..

O(N^5) 

前缀和:

#include<stdio.h>int map[50][50];int rui[51][51];int dat[50][50][50][50];int ans[51][51][51][51];int main(){int mx,my,query;scanf("%d%d%d",&mx,&my,&query);for(int i=0;i<mx;i++){for(int j=0;j<my;j++){char zan;scanf(" %c",&zan);map[i][j]=zan-'0';}}for(int i=0;i<mx;i++){for(int j=0;j<my;j++){rui[i+1][j+1]=rui[i+1][j]+rui[i][j+1]-rui[i][j]+map[i][j];}}for(int i=0;i<mx;i++){for(int j=0;j<my;j++){for(int k=i;k<mx;k++){for(int l=j;l<my;l++){if(rui[k+1][l+1]-rui[i][l+1]-rui[k+1][j]+rui[i][j]==0){dat[i][j][k][l]=1;}}}}}for(int i=0;i<mx;i++){for(int j=0;j<my;j++){for(int k=0;k<mx;k++){for(int l=0;l<my;l++){ans[i+1][j+1][k+1][l+1]=ans[i][j+1][k+1][l+1]+ans[i+1][j][k+1][l+1]+ans[i+1][j+1][k][l+1]+ans[i+1][j+1][k+1][l]-ans[i][j][k+1][l+1]-ans[i][j+1][k][l+1]-ans[i][j+1][k+1][l]-ans[i+1][j][k][l+1]-ans[i+1][j][k+1][l]-ans[i+1][j+1][k][l]+ans[i+1][j][k][l]+ans[i][j+1][k][l]+ans[i][j][k+1][l]+ans[i][j][k][l+1]-ans[i][j][k][l]+dat[i][j][k][l];}}}}for(int p=0;p<query;p++){int a,b,c,d;scanf("%d%d%d%d",&a,&b,&c,&d);a--;b--;c--;d--;printf("%d\n",ans[c+1][d+1][c+1][d+1]-ans[a][d+1][c+1][d+1]-ans[c+1][b][c+1][d+1]-ans[c+1][d+1][a][d+1]-ans[c+1][d+1][c+1][b]+ans[a][b][c+1][d+1]+ans[a][d+1][a][d+1]+ans[a][d+1][c+1][b]+ans[c+1][b][a][d+1]+ans[c+1][b][c+1][b]+ans[c+1][d+1][a][b]-ans[c+1][b][a][b]-ans[a][d+1][a][b]-ans[a][b][c+1][b]-ans[a][b][a][d+1]+ans[a][b][a][b]);}}


阅读全文
0 0
原创粉丝点击