Spotlights【思维+前缀和优化】
https://blog.csdn.net/mengxiang000000/article/details/53291883 原博客地址
http://codeforces.com/group/1EzrFFyOc0/contest/738/problem/B 题目链接
题目大意:
给你一个N*M的空间,其中0表示没有人,1表示有人,对应一个好位子以及方向的定义为:
①首先这个位子不能有人。
②其次对应这个位子安排一个照明方向,这个方向上必须有人才行。
让你求一共有多少个这样满足的放置方案。
思路:
1、首先我们O(n*m)暴力枚举出所有的没有人的位子。然后我们如果暴力判断其一行一列的四个方向是否有人的话,时间复杂度会高达:O(n^3)【我们若视n==m的情况下】显然会TLE。
2、那么我们考虑优化:
①设定sum【i】【j】表示第i行,从第一个数加到第j个数的和(前缀和),那么如果我们此时保证(i,j)是没有人的,并且sum【i】【j】>0,那么说明位子(i,j)的左侧有人,那么对应这个位子放置照明方向为左,即是一个可行解。那么同理,如果sum【i】【m】-sum【i】【j】>0,那么说明位子(i,j)的右侧有人,那么对应这个位子放置照明方向为右,即也是一个可行解。
②同理,再设定sum2【i】【j】表示第j列,从第一个数加到第i个数的和,那么同理,如果我们此时保证(i,j)是没有人的,并且sum2【i】【j】>0,那么说明位子(i,j)的上边有人,那么对应这个位子放置照明方向为上,即是一个可行解。那么也是同理,如果sum2【n】【j】-sum2【i】【j】>0,那么说明位子(i,j)的下边有人,那么对应这个位子放置照明方向为下,即也是一个可行解。
③那么此时我们暴力枚举出没有人的位子之后,只需要常数级的操作既可以搞定这个问题了。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<set> 7 #include<vector> 8 #include<stack> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 #define ll long long 13 #define se second 14 #define fi first 15 const int Mos = 0x7FFFFFFF; //2147483647 16 const int nMos = 0x80000000; //-2147483648 17 const int maxn=1e6+5; 18 19 int mp[1005][1005]; 20 int sum1[1005][1005],sum2[1005][1005]; 21 int n,m,cnt=0; 22 23 int main() 24 { 25 cin>>n>>m; 26 for(int i=1;i<=n;i++) 27 for(int j=1;j<=m;j++) 28 { 29 scanf("%d",&mp[i][j]); 30 sum1[i][j]=mp[i][j]+sum1[i][j-1]; //左到右累加 31 sum2[i][j]=mp[i][j]+sum2[i-1][j]; //上到下累加 32 } 33 for(int i=1;i<=n;i++) 34 for(int j=1;j<=m;j++) 35 { 36 if( mp[i][j] ) continue; 37 if(sum1[i][j]>0) cnt++; //左边有人 38 if(sum1[i][j]<sum1[i][m]) cnt++; //右边有人 39 if(sum2[i][j]>0) cnt++; //上边有人 40 if(sum2[i][j]<sum2[n][j]) cnt++; //下边有人 41 } 42 43 cout<<cnt<<endl; 44 }