Codeforces 372B Counting Rectangles is Fun:dp套dp
题目链接:http://codeforces.com/problemset/problem/372/B
题意:
给你一个n*m的01矩阵(1 <= n,m <= 40)。
然后有t组询问(a,b,c,d),问你:
在以(a,b)为左上角,以(c,d)为左下角,围成的矩形范围中,有多少全是0的矩形。
题解:
这题是dp套dp……
首先解决dp1:
表示状态:
f[a][b][c][d] = Rectangles number
表示左上角为(a,b),右下角的范围在(c,d)以内的全0矩形的个数。
如何转移:
f[a][b][c][d] = f[a][b][c-1][d] + f[a][b][c][d-1] - f[a][b][c-1][d-1] + check(a,b,c,d)
简单的容斥原理。
其中,如果左上角为(a,b),右下角为(c,d)的矩形中全是0,则check(a,b,c,d)为1,否则为0(要用到二维前缀和)。
边界条件:
set f = 0
复杂度O(N^4)。
然后解决dp2:
表示状态:
dp[a][b][c][d] = Rectangles number
表示在(a,b)和(c,d)围成的范围内的全0矩形个数。
显然有:
dp[a][b][c][d] = ∑ f[i][j][c][d] (a<=i<=c, b<=j<=d)
如何转移:
dp[a][b][c][d] = dp[a+1][b][c][d] + dp[a][b+1][c][d] - dp[a+1][b+1][c][d] + f[a][b][c][d]
还是根据容斥原理,不过在这里a,b,c,d要倒着枚举。
边界条件:
set dp = 0
复杂度O(N^4)。
所以对于每一次询问,直接输出dp[a][b][c][d]即可。
总复杂度O(N^4 + t)
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define MAX_N 45 5 6 using namespace std; 7 8 int n,m,t; 9 int v[MAX_N][MAX_N]; 10 int s[MAX_N][MAX_N]; 11 int f[MAX_N][MAX_N][MAX_N][MAX_N]; 12 int dp[MAX_N][MAX_N][MAX_N][MAX_N]; 13 14 void read() 15 { 16 cin>>n>>m>>t; 17 char c; 18 for(int i=1;i<=n;i++) 19 { 20 for(int j=1;j<=m;j++) 21 { 22 cin>>c; 23 v[i][j]=c-'0'; 24 } 25 } 26 } 27 28 void cal_s() 29 { 30 memset(s,0,sizeof(s)); 31 for(int i=1;i<=n;i++) 32 { 33 for(int j=1;j<=m;j++) 34 { 35 s[i][j]=s[i][j-1]+s[i-1][j]-s[i-1][j-1]+v[i][j]; 36 } 37 } 38 } 39 40 int check(int a,int b,int c,int d) 41 { 42 int sum=s[c][d]-s[c][b-1]-s[a-1][d]+s[a-1][b-1]; 43 return sum==0 ? 1 : 0; 44 } 45 46 void cal_f() 47 { 48 memset(f,0,sizeof(f)); 49 for(int a=1;a<=n;a++) 50 { 51 for(int b=1;b<=m;b++) 52 { 53 for(int c=a;c<=n;c++) 54 { 55 for(int d=b;d<=m;d++) 56 { 57 f[a][b][c][d]=f[a][b][c-1][d]+ 58 f[a][b][c][d-1]- 59 f[a][b][c-1][d-1]+ 60 check(a,b,c,d); 61 } 62 } 63 } 64 } 65 } 66 67 void cal_dp() 68 { 69 memset(dp,0,sizeof(dp)); 70 for(int a=n;a>=1;a--) 71 { 72 for(int b=m;b>=1;b--) 73 { 74 for(int c=n;c>=a;c--) 75 { 76 for(int d=m;d>=b;d--) 77 { 78 dp[a][b][c][d]=dp[a+1][b][c][d]+ 79 dp[a][b+1][c][d]- 80 dp[a+1][b+1][c][d]+ 81 f[a][b][c][d]; 82 } 83 } 84 } 85 } 86 } 87 88 void work() 89 { 90 cal_s(); 91 cal_f(); 92 cal_dp(); 93 int a,b,c,d; 94 while(t--) 95 { 96 cin>>a>>b>>c>>d; 97 cout<<dp[a][b][c][d]<<endl; 98 } 99 } 100 101 int main() 102 { 103 read(); 104 work(); 105 }