#1051. 画方框 (matrix)

题目描述

在前面的游戏中,由于moreD每次都用最优策略赢了他的宠物CD,CD现在很郁闷,于是他一个人在地板上画画东西了。别人都是说,“画个圈圈诅咒你”,但是CD很有特点,他喜欢“画个框框诅咒你…”。

现在我们把CD画的东西记录到一个N×N方阵上了,1表示CD画过的地方,0表示空白,请问CD最多可能画了多少不重复个方框呢?

方框就是所有以1为边的正方形,最小的方框是一个1,CD画方框的时候,是完全可能把两个不一样的方框的某些边重复画到同一个位置上的。参见样例。

输入格式

第一行输入一个整数N,1<=N<=1000。
接下来N行,每行N个数,1或者0。
输出格式

输出一个整数,表示CD最多可能画了多少不重复个方框。
样例
样例输入

3
1 1 0
1 1 0
0 0 0

样例输出

5

数据范围与提示

【样例输入2】

3

1 1 1

1 0 1

1 1 1

【样例输出2】

9

【数据描述】
对于30%的数据N<=100。
对于50%的数据N<=500。
对于100%的数据N<=1000。
来源

20121007
题 解 : 题解:
首 先 暴 力 统 计 , 但 首先暴力统计,但 N^3 太 大 。 太大。
所 以 考 虑 对 每 个 点 分 成 两 部 分 算 所以考虑对每个点分成两部分算
一 部 分 是 实 心 正 方 形 一部分是实心正方形
设 f [ i ] [ j ] 表 示 以 ( i , j ) 为 右 上 角 的 实 心 正 方 形 的 最 大 边 长 设f[i][j]表示以(i,j)为右上角的实心正方形的最大边长 f[i][j](i,j)
同 时 可 以 维 护 行 连 续 长 度 l 和 列 连 续 长 度 r 同时可以维护行连续长度l和列连续长度r lr
f [ i ] [ j ] = m i n ( f [ i − 1 ] [ j − 1 ] + 1 , m i n ( l , r ) ) ; f[i][j]=min(f[i-1][j-1]+1,min(l,r)); f[i][j]=min(f[i1][j1]+1,min(l,r));
这 时 可 以 优 化 时 间 a n s + = f [ i ] [ j ] 这时可以优化时间ans+=f[i][j] ans+=f[i][j]
另 一 部 分 暴 力 统 计 另一部分暴力统计

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 1005
using namespace std;
int n,m[N][N],sumh[N][N],suml[N][N],sum[N][N],f[N][N],l[N],r[N];
int ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			scanf("%d",&m[i][j]);
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			sumh[i][j]=sumh[i][j-1]+m[i][j];
			suml[i][j]=suml[i-1][j]+m[i][j];
			//sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+m[i][j];
		}
	}
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j){
			if(m[i][j])l[i]++,r[j]++;
			else l[i]=0,r[j]=0;
			if(f[i-1][j-1]+1>=min(l[i],r[j])){f[i][j]=min(l[i],r[j]);ans+=min(l[i],r[j]);continue;}
			f[i][j]=f[i-1][j-1]+1;ans+=f[i][j];
			//if(i==3&&j==3)cout<<f[i][j]<<endl;
			for(int k=f[i][j]+1;k<=min(l[i],r[j]);++k){
				int x=i-k+1,y=j-k+1;
				
				//if(sumh[i][y]-sumh[i][j-1]!=k||suml[x][j]-suml[i-1][j]!=k)break;
				if(sumh[x][j]-sumh[x][y-1]==k&&suml[i][y]-suml[x-1][y]==k)ans++;
				/*if(i==3&&j==3){
					cout<<k<<endl;
				    cout<<sumh[x][y]-sumh[x][j-1]<<" "<<suml[x][y]-suml[i-1][y]<<endl;
				}*/
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}
/*
3
1 1 1
1 0 1
1 1 1
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值