HDU 4331 Image Recognition

HDU 4331 Image Recognition

本题题目大意在一个01方阵中找出四条边全都是1的正方形的个数,对于正方形内部则没有要求。

一个直观的想法是首先用N^2的时间预处理出每一个是1的点向上下左右四个方向能够延伸的1的最大长度,记为四个数组l, r, u, d。然后我们观察到正方形有一个特征是同一对角线上的两个顶点在原方阵的同一条对角线上。于是我们可以想到枚举原来方阵的每条对角线,然后我们对于每条对角线枚举对角线上所有是1的点i,那么我们可以发现可能和i构成正方形的点应该在该对角线的 [i, i + min(r[i], d[i]) – 1] 闭区间内, 而在这个区间内的点 j 只要满足 j – i + 1 <= min(l[j], u[j]) 也就是满足j – min(l[j], u[j]) + 1 <= i,这样的 (i, j) 就能构成一个正方形。也就是说对于每条对角线,我们可以构造一个数组 a, 使得a[i] = i – min(l[i], u[i]) + 1

然后对这个数组有若干次查询,每次查询的是区间 [i, i + min(r[i], d[i]) – 1]内有多少个数满足 a[j] <= i,所有这些问题答案的和就是该问题的结果。对于这个问题,我们可以通过离线算法,先保存所有查询的区间端点,并对所有端点排序。然后使用扫描线算法,如果扫描到的是第i次查询的左端点,就让当前结果减去当前扫描过的数中 <= i的个数,如果扫描到的是第i次查询的有短点,则让当前结果加上当前扫描过的数中 <= i的个数,最后所有结果相加即可。

维护当前数出现的个数可以使用树状数组。这样对于每条对角线求结果的复杂度为O(nlogn),算法总的复杂度为O(n^2logn)。

HDU 4331 Image Recognition
HDU 4331 Image Recognition
View Code

View Code 
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<cstring>
#include<vector>
#include<string>
#define LL long long
using namespace std;
int map[1024][1024],l[1024][1024],u[1024][1024],d[1024][1024],r[1024][1024],a[2024],c[2024];
class Node{
public:
      bool left;
      int x,id;    
}p[2024];
bool cmp( Node a, Node b ){
    if( a.x == b.x ) return a.left;
    return a.x < b.x;    
}
int lowbit( int x ){
    return x&(-x);    
}
void Updata( int x, int n ){
    for( int i = x ; i <= n ; i += lowbit(i) )
          c[i] ++;    
}
int Query( int x ){
    int ans = 0;
    for( int i = x; i > 0 ; i -= lowbit(i) )
         ans += c[i];
    return ans;    
}
int res( int n, int m ){
    int ans = 0;
    memset( c , 0 , sizeof( c ) );
    sort( p , p + m , cmp );
    for( int i = 0 ; i < m ; i ++ )
         if( p[i].left ) {
                ans -= Query( p[i].id );
                Updata( a[p[i].x] ,n );
         }
         else ans +=Query( p[i].id );
//    printf( "__%d\n",ans );
    return ans;
}
int Solve( int n )
{
    int ans=0;
    for( int i =1 ; i <= n ; i ++ ){
        int m = 0;
        for( int j = 1 ; j <= i ; j ++ ){
                int x=n-i+j,y=j;         
                if( map[x][y] == 1 ){
                    a[y] = y - min( l[x][y],u[x][y] ) + 1;
                    p[m].left = true;p[m].id=y;p[m].x=y,p[m].id=y;
                    m++;
                    p[m].left=false;p[m].x=y+min( r[x][y],d[x][y] )-1;p[m].id=y;
                    m++;
                    }        
            }   
        ans += res( n ,m ); 
//        printf( "ans=%d\n",ans );   
      }    
      for( int i =2 ; i <= n ; i ++ ){
        int m = 0;
        for( int j = 1 ; j <= n - i + 1 ; j ++ ){
                  int x=j,y=i+j-1;             
                if( map[x][y] == 1 ){
                    a[y] = y - min( l[x][y],u[x][y] ) + 1;
                    p[m].left = true;p[m].id=y;p[m].x=y;
                    m++;
                    p[m].left=false;p[m].x=y+min( r[x][y],d[x][y] )-1;p[m].id=y;
                    m++;
                    }        
            }  
        ans += res( n ,m );   
//        printf( "ans=%d\n",ans ); 
      }    
      return ans;
}
int main(  ){
    int T,n;
    while( scanf( "%d",&T )==1 ){
        for( int cas = 1 ; cas <= T ;cas++ ){
            memset( u , 0 , sizeof( u ) );
            memset( d , 0 , sizeof( d ) );
            memset( l , 0 , sizeof( l ) );
            memset( r , 0 , sizeof( r ) );
             scanf( "%d",&n );
             LL cnt = 0,ans=0;
             for( int i = 1 ; i <= n ; i ++ )
                  for( int j = 1; j <= n ; j ++ ){
                       scanf( "%d",&map[i][j] ); 
                       if( map[i][j] == 0 ) u[i][j] = l[i][j] = 0;
                      else{
                        u[i][j] = u[i-1][j]  + 1;
                        l[i][j] = l[i][j-1] + 1;
                     }
                  }
            for( int i = n ; i >0  ; i -- ){
                 for( int j = n ;j > 0 ; j -- ){
                        if( map[i][j] == 0 ) d[i][j] = r[i][j] = 0;
                        else{
                        d[i][j] = d[i+1][j] + 1;
                        r[i][j] = r[i][j+1] + 1;
                       }
                     }
                }
            printf( "Case %d: %d\n",cas,Solve( n ) );
       }
   }
    //system( "pause" );
    return 0;
}

 

 

转载于:https://www.cnblogs.com/bo-tao/archive/2012/08/03/2622211.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/110357.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • Django(61)认证组件源码分析

    Django(61)认证组件源码分析认证组件源码入口APIView下的dispatch下的self.initial(request,*args,**kwargs),源码如下:definitial(self,request,

    2022年7月31日
  • docker镜像操作_docker主要特性

    docker镜像操作_docker主要特性前言Docker的三大核心概念:镜像、容器、仓库。初学者对镜像和容器往往分不清楚,学过面向对象的应该知道类和实例,这跟面向对象里面的概念很相似我们可以把镜像看作类,把容器看作类实例化后的对象。|

    2022年7月29日
  • endnote怎么修改参考文献上标(参考文献正文怎么标注)

    方法步骤如下:1、首先2113打开计算机,再打开Endnote,依次点击5261“Edit”——4102“OutputStyles”——“OpenStyleManager”。2、在弹出的窗1653口中,选择相近的参考文献格式,点击红色框线2处的“StyleInfo/preview”对已选的参考文献格式进行预览,这里随机选了“CurrentOpinionLipid”,仅此作为示例。也可以…

    2022年4月15日
  • 北京上网首选DNS服务器地址,北京最快的DNS服务器地址,北京DNS大全

    北京上网首选DNS服务器地址,北京最快的DNS服务器地址,北京DNS大全为了提高北京上网用户打开网页的速度,北京上网用户要选择适合北京网络的DNS,很多时候北京上网用户在家或者在办公室上网,经常发现能够上网,但很多的网站和网址打不开,报解析错误,这种情况往往是属于您的DNS使用不当,有时选北京电信联通推荐的DNS也会出现这种情况,具体选那个,之前最好去ping一下,看哪个延迟小一般情况下还是要选择北京电信联通移动的DNS。下面给您推荐在北京常用的DNS。北

    2022年6月4日
  • SM4加密Java实现

    SM4加密Java实现可直接使用,参考csdn上一位老哥的。packagecom.hps.test2;importjava.util.Arrays;publicclassSMS4{privatestaticfinalintENCRYPT=1;privatestaticfinalintDECRYPT=0;publicstaticfinalintROUND=32;…

    2022年9月27日
  • LaTeX参考文献引用显示?问号解决办法!!!!「建议收藏」

    LaTeX参考文献引用显示?问号解决办法!!!!「建议收藏」在使用Latex之前,我们一般会借用已有的论文模板,在模板基础上加入我们自己的文章内容,随后编译成PDF文件,其基本流程就是:Latex->Bibtex->Latext->Latex。1、第一步点击Latex编译,可以获得*.aux文件、.dvi文件、.log文件以及*.gz文件;2、第二步点击Bibtex编译,可以获得*.blg(性能监视器文件)和*.bbl文件;3、第三…

    2022年9月9日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号