• 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 }
  • 相关阅读:
    页面可视化搭建 整理
    单页面应用(SPA)重新部署后,正在浏览的页面如何更新缓存?
    vim 使用
    浏览器缓存 知识点
    http 2.0 新特性
    GoJS 在 vue 项目中的使用
    详解Vue中watch的高级用法
    什么是 PWA?
    代码风格统一工具:EditorConfig 和 静态代码检查工具:ESLint
    vue-cli 3.x 使用
  • 原文地址:https://www.cnblogs.com/Leohh/p/8232383.html
Copyright © 2020-2023  润新知