ACM-ICPC 2018 南京赛区网络预赛 B The writing on the wall(暴力)

题目链接

题意:一个n*m的方格矩阵,有的格子被涂成了黑色,问该矩阵中有多少个子矩阵,子矩阵不包含黑色格子;

思路:对于一个长为L, 高为H的无黑点矩阵中包含的高为H的子矩阵个数为L+(L-1)+(L-2)+…+1个;这是直接算的一种方法;如何程序表示该计算呢?


  
  
  1. for( int i= 1; i<=L; i++){
  2. for( int j=i; j> 0; j–){
  3. count+= 1;
  4. }
  5. }

这样的一个双层循环就表示了上式;那么所有子矩阵个数就是三层循环,高由1->H:


  
  
  1. for( int h= 1; h<=H; h++){
  2. for( int i= 1; i<=L; i++){
  3. for( int j=i; j> 0; j--){
  4. count+=h;
  5. }
  6. }
  7. }

这是其中没有黑点的;如果在某处加了个黑点又如何计算呢?如下图:

先看高为H(4)的子矩阵个数:以(4, 7)为右下角的高为H的子矩阵个数为3个,由L=4处在向左,就只能构成高为2的子矩阵了;

那么怎么该上边的代码才能得出答案呢?如下:


  
  
  1. for( int i= 1; i<=H; i++){
  2. for( int j= 1; j<=L; j++){
  3. h=i;
  4. for( int k=j; k> 0; k--){
  5. h=min(h, i-p[k]);
  6. count+=h;
  7. }
  8. }
  9. }
  10. //p[k]表示第k列中在i行上边的第一个黑点的位置,

上边代码就是本题的核心代码了;然后H用n代替,L用m代替,这样复杂度为O(n*m*m);然后标记黑点的位置每次维护h就可以了;


  
  
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. int b[ 100010][ 110], up[ 110];
  5. int main(){
  6. int T, cas= 0;
  7. scanf( "%d", &T);
  8. while(T--){
  9. int n, m, K;
  10. scanf( "%d%d%d", &n, &m, &K);
  11. for( int i= 0; i<=n; i++){
  12. for( int j= 0; j<=m; j++){
  13. b[i][j]= 0;
  14. up[j]= 0;
  15. }
  16. }
  17. for( int i= 0; i<K; i++){
  18. int x, y;
  19. scanf( "%d%d", &x, &y);
  20. b[x][y]= 1;
  21. }
  22. ll ans= 0;
  23. for( int i= 1; i<=n; i++){
  24. for( int j= 1; j<=m; j++){
  25. if(b[i][j]){
  26. up[j]=i;
  27. }
  28. }
  29. for( int j= 1; j<=m; j++){
  30. ll minn= 0x7f7f7f7f7f7f7f7f;
  31. for( int k=j; k> 0; k--){
  32. minn=min(minn, (ll)(i-up[k]));
  33. ans+=minn;
  34. }
  35. }
  36. }
  37. printf( "Case #%d: %lld\n", ++cas, ans);
  38. }
  39. return 0;
  40. }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值