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 }

 

posted @ 2018-01-07 21:58  Leohh  阅读(372)  评论(0编辑  收藏  举报