小小明系列故事——游戏的烦恼
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 960 Accepted Submission(s): 341
Problem Description
小小明最近在玩一款游戏,它由n*m大小的矩阵构成,矩阵上会随机产生一些黑色的点,这些点它们可能会连在一起也可能会分开,这些点的个数没有限制,但是每个1*1方格中最多只可能有一个黑点产生。游戏要求玩家以最短的时间用x*y的小矩阵覆盖这个大矩阵,覆盖的要求有以下2点:
1. x*y大小的小矩阵内必须有x*y个黑点。
2. 多个小矩阵可以重叠,但是每个小矩阵放置的位置必须是独一无二的,即不同的小矩阵内的黑点不能完全相同。例如1*2的矩阵可以横着放,也可以竖着放,这两种方法是不同的,即使它们可能共用黑点。
小小明是个粗心的孩子,他尝试了很多遍都无法将所有的符合要求的小矩阵找到,聪明的你,能不能告诉烦恼中的小小明这个大矩阵里有多少个满足要求的小矩阵呢?
1. x*y大小的小矩阵内必须有x*y个黑点。
2. 多个小矩阵可以重叠,但是每个小矩阵放置的位置必须是独一无二的,即不同的小矩阵内的黑点不能完全相同。例如1*2的矩阵可以横着放,也可以竖着放,这两种方法是不同的,即使它们可能共用黑点。
小小明是个粗心的孩子,他尝试了很多遍都无法将所有的符合要求的小矩阵找到,聪明的你,能不能告诉烦恼中的小小明这个大矩阵里有多少个满足要求的小矩阵呢?
Input
题目有多组测试数据(不多于100个);
每组测试数据的第一行包含2个正整数n和m,然后第二行是x和y(n,m,x,y的意思如题),接下来n行,每行m个字符,其中’ * ’表示黑点,’ . ’表示空白。
n和m为0则结束输入。
[Technical Specification]
0 < n, m <= 2000
0 < x, y <= 1000
每组测试数据的第一行包含2个正整数n和m,然后第二行是x和y(n,m,x,y的意思如题),接下来n行,每行m个字符,其中’ * ’表示黑点,’ . ’表示空白。
n和m为0则结束输入。
[Technical Specification]
0 < n, m <= 2000
0 < x, y <= 1000
Output
请计算并输出一共有多少个满足要求的小矩阵,每组输出占一行。
Sample Input
2 3
1 2
**.
.**
0 0
Sample Output
3
Source
思路:
暴力枚举。
用前缀和数组记录ma[i][j]有多少个'*',那后暴力枚举每个‘*’,看在当前的点到另一个对角点之间共有多少个‘*’,这个查询为O(1)
k=a[nx][ny]-a[nx][y-1]-(a[x-1][ny]-a[x-1][y-1]);在判断下这里面的点的个数是否是这个矩阵的大小。
1 #include<stdio.h> 2 #include<algorithm> 3 #include<iostream> 4 #include<string.h> 5 #include<math.h> 6 #include<queue> 7 #include<string.h> 8 #include<stack> 9 #include<vector> 10 #include<map> 11 #define sc(x) scanf("%I64d",&x) 12 #define pr(x) printf("%I64d",x) 13 #define prr(x) printf("%I64d ",x) 14 #define prrr(x) printf(" %I64d",x) 15 #define FOR(i,p,q) for(int i=p;i<=q;i++) 16 int ch(int x,int y,int z,int t); 17 using namespace std; 18 char ma[2001][2001]; 19 int a[2001][2001]; 20 int p,q; 21 int main(void) 22 { 23 int n,i,j,k; 24 int nn,mm; 25 while(scanf("%d %d",&p,&q),p!=0||q!=0) 26 { 27 memset(a,0,sizeof(a)); 28 scanf("%d %d ",&nn,&mm); 29 for(i=1; i<=p; i++) 30 { 31 gets(ma[i]+1); 32 } 33 for(i=1; i<=p; i++) 34 { 35 for(j=1; j<=q; j++) 36 { 37 if(ma[i][j]=='*') 38 { 39 a[i][j]=a[i][j-1]+1; 40 } 41 else 42 { 43 a[i][j]=a[i][j-1]; 44 } 45 } 46 }for(i=1;i<=q;i++) 47 { 48 for(j=1;j<=p;j++) 49 { 50 a[j][i]+=a[j-1][i]; 51 } 52 } 53 int sum=0; 54 for(i=1;i<=p;i++) 55 { 56 for(j=1;j<=q;j++) 57 { 58 if(ma[i][j]='*') 59 { 60 sum+=ch(i,j,nn,mm);//以当前的点为左上定点找长为nn宽为mm的矩阵 61 sum+=ch(i,j,mm,nn);//以当前的点为左上定点找长为mm宽为nn的矩阵 62 } 63 } 64 } 65 if(nn==mm)//如果长和宽相等那么上面所找的两种矩阵就一样,所以/2; 66 { 67 sum/=2; 68 } 69 printf("%d ",sum); 70 } 71 return 0; 72 73 } 74 75 int ch(int x,int y,int z,int t)//判断当前所选矩阵的‘*’的个数是否符合矩阵的大小 76 { 77 int n,i,j,k; 78 int nx=x+z-1; 79 int ny=y+t-1; 80 if(nx<=p&&ny<=q)//判断是否超边界 81 { 82 k=a[nx][ny]-a[nx][y-1]-(a[x-1][ny]-a[x-1][y-1]); 83 if(k==z*t) 84 { 85 return 1; 86 } 87 }return 0; 88 89 }