[2013腾讯马拉松 3月23日]HDU 4517 小小明系列故事——游戏的烦恼

腾讯马拉松,我报的是3月23日的那场。其他的几场也看了,不过毕竟其他几日做的是看客,自然也没费劲去思考,23日这场是自己做的,所以比较认真一些。现场AC了3题,分别是A,C,E,做完这3道已经接近1个半小时了,看了提交貌似另外两道很难,无力再去开题了。A题没注意标准时间输出WA了一次,其他1A。由于罚时少,RANK刚好挤进了前50,运气还不错。

貌似3月25日的题目最难……只要一题就能够出线,一个报了这场的学姐不知是否顺利晋级。

其中A,E题是水题。A题是计算日期,老生常谈的东西,不说了;E题是典型的流水线模型,稍微一琢磨就能AC。

至于另外两个题……,B题很直白,因式分解,记得在12年某场网络赛上见过这类题,这种神题小白怎么敢碰呢。D题倒是感觉是一道数位DP?(不是很清楚),先不去搜报告了,等有空自己思考思考。

这里主要说说C题。题意抽象成模型其实就是求一个大的点阵,被'*'和'.'填充,找满足有多少个x*y的矩阵,使得矩阵内的点全是'*',x*y横放竖放都行。点阵大小2000*2000。

暴力么的,就不要想了,时间复杂度N的好几次方了。

说到优化,首先想到2维线段树在时间复杂度上应该勉强能卡过此题,不过线段树要求空间太大,就这个题的数据量而言,此路不通。

后来想到,这个题所执行的功能仅仅是查询,是一个完全静态的问题,线段树所就有点大材小用了,想到这里貌似找到突破口。

静态问题,常用的解题策略就是预处理。这个题我想到的方法是把方阵看成01阵,'*'代表1。然后预处理sum[i,j],sum[i,j]代表[1,1]~[i,j]这个矩阵的和。那么很明显

sum[i,j]=val[i,j]+sum[i,j-1]+sum[i-1,j]-sum[i-1,j-1]。预处理的时间复杂度是O(n*m*1)。

剩下的工作就是统计了,x*y的矩阵横竖都扫一遍,找到大小为x*y的子阵和为x*y的,结果就+1。

对于x*y的矩阵来说判断条件是:sum[i][j]-sum[i][j-y]-sum[i-x][j]+sum[i-x][j-y]==x*y

对于y*x的矩阵来说判断条件是:sum[i][j]-sum[i][j-x]-sum[i-y][j]+sum[i-y][j-x]==x*y

判定的时间复杂度是O(2*n*m*1)。所以该方法的时间复杂度是O(n*m)。

这题有个trap,x==y的时候,只统计一次就好。初始化sum的时候最好不要memset,很容易超时,手动写循环。当时用memset,900+MS卡过,吓尿了。

说到这里貌似就完了。不过我想另外扩展一下。如果这个题需要动态维护矩阵信息,如修改某一点的值,该怎么做?

修改sum[][]的值显然不现实,复杂度太高。线段树可解,可是内存会爆掉。有没有更好的办法?有的,需要用到位运算的思想,具体的做法这里不详细讲了,有兴趣的可以去查一下资料。

View Code
 1 #include <map>
 2 #include <set>
 3 #include <list>
 4 #include <queue>
 5 #include <stack>
 6 #include <cmath>
 7 #include <ctime>
 8 #include <vector>
 9 #include <bitset>
10 #include <cstdio>
11 #include <string>
12 #include <numeric>
13 #include <cstring>
14 #include <cstdlib>
15 #include <iostream>
16 #include <algorithm>
17 #include <functional>
18 using namespace std;
19 typedef long long ll;
20 #define exp 1e-8
21 #define inf 0x7fffffff
22 #define read freopen("in.txt","r",stdin)
23 #define write freopen("out.txt","w",stdout)
24 #define maxn 2005
25 #define maxe maxn*maxn*2
26 int mp[maxn][maxn];
27 char ss[maxn];
28 int main()
29 {
30     //read;
31     int n,m;
32     while(~scanf("%d%d",&n,&m)&&(n+m))
33     {
34         int x,y;
35         scanf("%d%d",&x,&y);
36         for(int i=0;i<=n;i++)
37             for(int j=0;j<=m;j++)mp[i][j]=0;
38         for(int i=0;i<n;i++)
39         {
40             scanf("%s",ss);
41             for(int j=0;j<m;j++)if(ss[j]=='*')mp[i+1][j+1]=1;
42         }
43         for(int i=1;i<=n;i++)
44             for(int j=1;j<=m;j++)
45                 mp[i][j]=mp[i][j]+mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];
46         int tt=x*y;
47         ll ans=0;
48         for(int i=x;i<=n;i++)
49             for(int j=y;j<=m;j++)
50                 if(mp[i][j]-mp[i][j-y]-mp[i-x][j]+mp[i-x][j-y]==tt)ans++;
51         if(x!=y)for(int i=y;i<=n;i++)
52             for(int j=x;j<=m;j++)
53                 if(mp[i][j]-mp[i][j-x]-mp[i-y][j]+mp[i-y][j-x]==tt)ans++;
54         printf("%I64d\n",ans);
55     }
56     return 0;
57 }
原文地址:https://www.cnblogs.com/mcflurry/p/2982292.html