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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JQuery的Ajax跨域请求的

    JQuery的Ajax跨域请求的

    2022年2月2日
    40
  • mac版的goland激活码【中文破解版】「建议收藏」

    (mac版的goland激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月30日
    537
  • 进销存管理系统【源码开放】[通俗易懂]

    进销存管理系统【源码开放】[通俗易懂]进销存管理系统的功能需求:1,实现采购订单的持久化,对采购商品入库处理,还有就是采购的退货处理;2,实现商品的入库、出库操作,查询商品的库存信息,修改商品的仓库号3,实现销售订单的添加,销售发货处理,并且销售的退货处理4,实现新建员工培训信息和查询员工培训记录功能5,实现对商品、供应商、客户资料的管理,对员工用户的管理,最重要的是对系统数据的备份和恢复代码的截图如下所示:系统的截图如下所示:bean层manage的代码如下所示:packag.

    2022年5月31日
    30
  • 进程调度有可抢占 哪种开销更大_什么时候用多线程什么时候用多进程

    进程调度有可抢占 哪种开销更大_什么时候用多线程什么时候用多进程线程调度为什么比进程调度更少开销?在对比进程调度与线程调度的开销前,我们需要明白两点:进程与线程的差异任务调度的开销进程与线程的差异我们首先要明白,线程和进程有什么关系?从概念上来讲,线程是进程的一部分,只是任务调度相关的部分,所以我们才说,“线程是调度的最小单位”。进程拥有着资源,这些资源不属于某一个特定线程,因为所有线程共享进程拥有的资源,所以我们才说,“进程是资源分配的最小单位…

    2025年11月11日
    3
  • android Gradle 教程

    android Gradle 教程发现一个官方翻译后的gradle教程:http://avatarqing.github.io/Gradle-Plugin-User-Guide-Chinese-Verision/index.html

    2022年6月28日
    30
  • qt tabwidget使用_word横向表格变竖向

    qt tabwidget使用_word横向表格变竖向QTabWidget竖向QTabBar横向

    2022年9月23日
    6

发表回复

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

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