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 }

猜你喜欢

转载自www.cnblogs.com/thunder-110/p/9279493.html