zoukankan      html  css  js  c++  java
  • HDU 4331 Image Recognition [边上全为1构成的正方形个数]

      首先能够构成正方形的两个对顶点肯定在同一条对角线上,可以想到依次处理每条对角线上的点。

      对于每个点,预处理出它能到的四个方向的连续1最多有多少个,记为p_up,p_down,p_left,p_right,显然,决定某一个点向右下能延伸的多少只取决于p_down和p_right中的较小值,决定某一个点向左上能延伸到多少只取决于p_up和p_left的较小值。

      

      对于每个点,记录它能到达的最右的x轴的绝对坐标,并记录它自身的y坐标。

      统计一个点和它左上的点(在对角线上)能组成多少个正方形时,只要判断有多少个点向右能和它相交即可。比如统计5,只要记录1~4中有多少点向右能和红线交叉,显然5可以和1,3,4组成边上全部为1的正方形。

      HDU给的题解没太看懂,我是用一个堆维护每个点能到的最右的x轴坐标,当堆顶元素向右不能到达该点的x坐标时,就可以将这个点删除,因为这个点已经没有用了,比如统计5时,就可以将2这个点删除,它已经不能和5以及以后的点组成正方形,然后再统计红线范围内有多少点即可,这里用树状数组线段树什么的都可以。

      另外这题如果不一条条对角线分别统计会MLE。。。可能是以为我用了堆的缘故吧。。

     

     1 #include <string.h>
     2 #include <stdio.h>
     3 #include <queue>
     4 #define MAXN 1005
     5 using namespace std;
     6 typedef pair<int,int> pii;
     7 typedef __int64 LL;
     8 int cas,n,mz[MAXN][MAXN],d[MAXN][MAXN][4];
     9 int c[MAXN];
    10 int lowbit(int x){return x&-x;}
    11 void update(int k,int d){
    12     while(k<n+1)c[k]+=d,k+=lowbit(k);
    13 }
    14 int getans(int k){
    15     int ret=0;
    16     while(k)ret+=c[k],k-=lowbit(k);
    17     return ret;
    18 }
    19 int main(){
    20     //freopen("test.in","r",stdin);
    21     scanf("%d",&cas);
    22     for(int ca=1;ca<=cas;ca++){
    23         scanf("%d",&n);
    24         memset(mz,0,sizeof mz);
    25         for(int i=1;i<=n;i++)
    26             for(int j=1;j<=n;j++)
    27                 scanf("%d",&mz[i][j]);
    28         //计算最长能延伸到4个方向的距离
    29         //0:left-> 1:right<- 2:top 3:bottom
    30         for(int i=1;i<=n;i++)
    31             for(int j=1;j<=n;j++)
    32                 d[i][j][0]=mz[i][j]?d[i][j-1][0]+1:0,
    33                 d[i][j][2]=mz[i][j]?d[i-1][j][2]+1:0;
    34         for(int i=n;i>=1;i--)
    35             for(int j=n;j>=1;j--)
    36                 d[i][j][1]=mz[i][j]?d[i][j+1][1]+1:0,
    37                 d[i][j][3]=mz[i][j]?d[i+1][j][3]+1:0;
    38         LL ans=0;
    39         //枚举对角线,能构成正方形的点的对顶点必然在一条对角线上
    40         for(int dt=-n+1;dt<=n-1;dt++){
    41             //用堆维护该对角线上向左和向右都能延伸到当前点的集合
    42             //并用树状数组统计某个区间内能到达该点的点的数量
    43             priority_queue<pii,vector<pii>,greater<pii> > q;
    44             memset(c,0,sizeof c);
    45             for(int i=1-dt>0?1-dt:1;i<=n&&i+dt<=n;i++){
    46                 int j=i+dt;
    47                 if(mz[i][j]==0)continue;
    48                 if(d[i][j][3]<d[i][j][1])d[i][j][1]=d[i][j][3];
    49                 if(d[i][j][2]<d[i][j][0])d[i][j][0]=d[i][j][2];
    50                 q.push(pii(j-1+d[i][j][1],i));
    51                 update(i,1);
    52                 while(!q.empty()&&q.top().first<j){
    53                     update(q.top().second,-1);
    54                     q.pop();
    55                 }
    56                 ans+=getans(i)-getans(i-d[i][j][0]);
    57             }
    58         }
    59         printf("Case %d: %I64d\n",ca,ans);
    60 
    61 
    62     }
    63     return 0;
    64 }
  • 相关阅读:
    使用kindeditor获取不到富文本框中的值
    ASP.NET中的文件操作(文件信息,新建,移动,复制,重命名,上传,遍历)
    2018 遇到selenium.common.exceptions.WebDriverException问题
    DataTable与实体类互相转换
    反射load,loadfile,LoadFrom区别
    DbSet.Attach(实体)与DbContext.Entry(实体).State = EntityState.Modified 区别
    .net 面试总结
    C# Linq 常用查询操作符
    windows下nginx的安装及使用
    熊猫热土-环汶川50公里越野赛赛记
  • 原文地址:https://www.cnblogs.com/swm8023/p/2661253.html
Copyright © 2011-2022 走看看