【杭电2015年12月校赛F】【二维DP】01 Matrix 大正方形内size为k的全1子正方形的个数

来源:互联网 发布:sql server进阶 编辑:程序博客网 时间:2024/06/05 10:02

01 Matrix

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 636    Accepted Submission(s): 139


Problem Description
It's really a simple problem. 
Given a "01" matrix with size by n*n (the matrix size is n*n and only contain "0" or "1" in each grid), please count the number of "1" matrix with size by k*k (the matrix size is k*k and only contain "1" in each grid).
 

Input
There is an integer T (0 < T <=50) in the first line, indicating the case number.
Each test case begins with two numbers n and m (0<n, m<=1000), specifying the size of matrix and the query number.
Then n lines follow and each line contains n chars ("0" or "1").
Then m lines follow, each lines contains a number k (0<k<=n).
 

Output
For each query, output the number of "1" matrix with size by k*k.
 

Sample Input
22 20100123 3010111111122
 

Sample Output
10722
 




【杭电2015年12月校赛F】【二维DP O(n^2)做法】01 Matrix 大正方形内size为k的全1子正方形的个数

#include<stdio.h>#include<iostream>#include<string.h>#include<string>#include<ctype.h>#include<math.h>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=1010,M=0,Z=1e9+7,ms63=0x3f3f3f3f;int casenum,casei;int n,m;char s[N][N];int d[N][N];int f[N];int main(){    scanf("%d",&casenum);    for(casei=1;casei<=casenum;++casei)    {MS(f,0);        scanf("%d%d",&n,&m);        for(int i=1;i<=n;++i)scanf("%s",s[i]+1);        for(int i=1;i<=n;++i)        {            for(int j=1;j<=n;++j)            {if(s[i][j]=='0')d[i][j]=0;else{int k=d[i-1][j-1];gmin(k,d[i-1][j]);gmin(k,d[i][j-1]);d[i][j]=k+1;++f[k+1];}            }        }        for(int i=n;i>=2;--i)f[i-1]+=f[i];        while(m--)        {            int k;            scanf("%d",&k);            printf("%d\n",f[k]);        }    }    return 0;}/*【题意】T(50)组数据每组数据给你一个n*n(1<=n<=1000)的01矩阵同时有m(1<=m<=1000)个询问对于每个询问,有尺寸k,让你求出,这个大的01矩阵中,有多少个size为k*k的小矩阵,满足小矩阵的每个数字都为1。【类型】DP【分析】询问辣么多!于是显然,我们直接预处理出每个size的矩形的个数就好啦。然后怎么做呢?提供两种做法:做法1,首先你要会一个最基本的,利用二维前缀和 求二维子矩阵数值和的做法利用这个做法,可以查询一个子矩阵是否为全1矩阵。然后,我们枚举子矩阵的右下角位置,然后二分得到——"以这个位置为右下角的,最大的全1正方形的size是多少"如果size为l,意味着size={1~l}的全1正方形的计数会各多1个。我们可以只计数++f[l];然后我们把f[]从大到小扫描一遍,f[i-1]+=f[i]。最后的f[k]就是大小为k的全1正方形的个数啦。时间复杂度O(n^2 logn)做法2,我们用d[i][j]表示右下角为(i,j)的最大的全1正方形的size是多少。那么直接有一个DP转移if(s[i][j]=='1')d[i][j]=max(d[i-1][j],max(d[i][j-1],d[i-1][j-1]))+1;else d[i][j]=0;然后一样计数++f[d[i][j]]最后扫描一遍就可以啦。时间复杂度O(n^2)*/

【杭电2015年12月校赛F】【二维DP 二分O(n^2logn)做法】01 Matrix 大正方形内size为k的全1子正方形的个数

#include<stdio.h>#include<algorithm>#include<ctype.h>#include<string.h>using namespace std;int casenum,casei;typedef long long LL;const int N=1005;int n,m;char s[N][N];int a[N][N];int line[N];int f[N];int main(){    scanf("%d",&casenum);    for(casei=1;casei<=casenum;++casei)    {        scanf("%d%d",&n,&m);        for(int i=1;i<=n;++i)scanf("%s",s[i]+1);        memset(line,0,sizeof(line));        memset(f,0,sizeof(f));        for(int i=1;i<=n;++i)        {            for(int j=1;j<=n;++j)            {                line[i]+=(s[i][j]=='1');                a[i][j]=a[i-1][j]+line[i];                if(s[i][j]=='1')                {                    int l=1;                    int r=min(i,j);                    while(l<r)                    {                        int mid=(l+r+1)>>1;                        int sum=a[i][j]-a[i-mid][j]-a[i][j-mid]+a[i-mid][j-mid];                        if(sum==mid*mid)l=mid;                        else r=mid-1;                    }                    ++f[l];                }            }        }        for(int i=n;i>=2;--i)f[i-1]+=f[i];        while(m--)        {            int k;            scanf("%d",&k);            printf("%d\n",f[k]);        }    }    return 0;}/*【题意】T(50)组数据每组数据给你一个n*n(1<=n<=1000)的01矩阵同时有m(1<=m<=1000)个询问对于每个询问,有尺寸k,让你求出,这个大的01矩阵中,有多少个size为k*k的小矩阵,满足小矩阵的每个数字都为1。【类型】DP【分析】询问辣么多!于是显然,我们直接预处理出每个size的矩形的个数就好啦。然后怎么做呢?提供两种做法:做法1,首先你要会一个最基本的,利用二维前缀和 求二维子矩阵数值和的做法利用这个做法,可以查询一个子矩阵是否为全1矩阵。然后,我们枚举子矩阵的右下角位置,然后二分得到——"以这个位置为右下角的,最大的全1正方形的size是多少"如果size为l,意味着size={1~l}的全1正方形的计数会各多1个。我们可以只计数++f[l];然后我们把f[]从大到小扫描一遍,f[i-1]+=f[i]。最后的f[k]就是大小为k的全1正方形的个数啦。时间复杂度O(n^2 logn)做法2,我们用d[i][j]表示右下角为(i,j)的最大的全1正方形的size是多少。那么直接有一个DP转移if(s[i][j]=='1')d[i][j]=min(d[i-1][j],min(d[i][j-1],d[i-1][j-1]))+1;else d[i][j]=0;然后一样计数++f[d[i][j]]最后扫描一遍就可以啦。时间复杂度O(n^2)*/


0 0
原创粉丝点击