Codeforce 373 D Counting Rectangles is Fun (统计全0子矩阵)

谁借莪1个温暖的怀抱¢ 2022-09-20 15:13 196阅读 0赞

题目链接:http://codeforces.com/contest/373/problem/D

题意:求一个矩阵中有多少个全0子矩阵。

思路:动态规划,dp[a][b][c][d]为待求量,矩阵大小只有40*40,询问数量可以达到3*10^5,提示应该进行预处理。

状态转移方程:dp[a][b][c][d]= dp[a][b][c-1][d] + dp[a][b][c][d-1] - dp[a][b][c-1][d-1]+val

val代表在矩阵(a,b)(c,d)中以(c,d)为右下角的全0矩阵的个数

预处理数组top[i][j]表示点(i,j)向上能延伸到最远的0的位置,O(n)向左扫出矩阵的个数。

总体复杂度O(n^5)

  1. #include <cstdio>
  2. #define min(a,b) ((a)<(b)?(a):(b))
  3. const int N=42;
  4. int dp[N][N][N][N];
  5. char g[N][N];
  6. int top[N][N];
  7. int main()
  8. {
  9. int n,m,q,i,j;
  10. scanf("%d%d%d",&n,&m,&q);
  11. for (i=1;i<=n;i++)
  12. {
  13. scanf("%s",g[i]+1);
  14. for (j=1;j<=m;j++)
  15. if (g[i][j]=='0')
  16. top[i][j]=top[i-1][j]+1;
  17. else
  18. top[i][j]=0;
  19. }
  20. int a,b,c,d;
  21. for (a=1;a<=n;a++) for (b=1;b<=m;b++)
  22. for (c=a;c<=n;c++) for (d=b;d<=m;d++)
  23. {
  24. dp[a][b][c][d]= dp[a][b][c-1][d] + dp[a][b][c][d-1] - dp[a][b][c-1][d-1];
  25. int minH = min(top[c][d],c-a+1);
  26. for (i=d;i>=b;i--)
  27. {
  28. minH = min(top[c][i],minH);
  29. if (minH==0) break;
  30. else dp[a][b][c][d] += minH;
  31. }
  32. }
  33. while (q--)
  34. {
  35. scanf("%d%d%d%d",&a,&b,&c,&d);
  36. printf("%d\n",dp[a][b][c][d]);
  37. }
  38. return 0;
  39. }

下面一份代码参考了:http://mochavic.blog.163.com/blog/static/2196651172013111402949522/

利用了部分和的思想,复杂度O(n^4),但因为循环次数多,所以实际速度没有上面的快

  1. #include <cstdio>
  2. const int N=42;
  3. int s[N][N];
  4. char str[N];
  5. int Cal (int x0, int y0, int x1, int y1)
  6. {
  7. x0--; y0--;
  8. return s[x1][y1] - s[x0][y1] - s[x1][y0] + s[x0][y0];
  9. }
  10. int dp[N][N][N][N];
  11. int val[N][N][N][N];
  12. int main ()
  13. {
  14. int n,m,q,i,j;
  15. scanf("%d%d%d",&n,&m,&q);
  16. for (i=1;i<=n;i++)
  17. {
  18. scanf("%s",str);
  19. for (j=0;j<m;j++)
  20. s[i][j + 1] = s[i][j] + str[j] - '0';
  21. }
  22. for (i=1;i<=n;i++)
  23. for (j=0;j<m;j++)
  24. s[i][j] += s[i - 1][j];
  25. //s[i][j]预处理出了(0,0,i,j)范围内所有1的个数
  26. int x0, x1, y0, y1;
  27. for (x0 = 1; x0 <= n; x0++)
  28. for (x1 = x0; x1 <= n; x1++)
  29. for (y0 = 1; y0 <= m; y0++)
  30. for (y1 = y0; y1 <= m; y1++)
  31. if (Cal(x0, y0, x1, y1) == 0)
  32. val[x0][y0][x1][y1]++; //(x0,y0,x1,y1)范围内全0
  33. for (x1 = 1; x1 <= n; x1++)
  34. for (y1 = 1; y1 <= m; y1++)
  35. {
  36. for (i = n; i >= 1; i--)
  37. for (j = m; j >= 1; j--)
  38. val[i][j - 1][x1][y1] += val[i][j][x1][y1];
  39. for (i = n; i >= 1; i--)
  40. for (j = m; j >= 1; j--)
  41. val[i - 1][j][x1][y1] += val[i][j][x1][y1];
  42. }
  43. //val[x0][y0][x1][y1]为以x1,y1为右下角的左上角不超过x0,y0的全0矩阵个数
  44. for (x0 = 1; x0 <= n; x0++) for (x1 = x0; x1 <= n; x1++)
  45. for (y0 = 1; y0 <= m; y0++) for (y1 = y0; y1 <= m; y1++)
  46. dp[x0][x1][y0][y1] = dp[x0][x1 - 1][y0][y1] + dp[x0][x1][y0][y1 - 1] - dp[x0][x1 - 1][y0][y1 - 1] + val[x0][y0][x1][y1];
  47. while (q--)
  48. {
  49. scanf("%d%d%d%d", &x0, &y0, &x1, &y1);
  50. printf("%d\n", dp[x0][x1][y0][y1]);
  51. }
  52. return 0;
  53. }

发表评论

表情:
评论列表 (有 0 条评论,196人围观)

还没有评论,来说两句吧...

相关阅读