Codeforces 372B Counting Rectangles is Fun:dp套dp

Leohh發表於2018-01-07

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

 

相關文章