題目連結: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 }