您的位置:首页 > 其它

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

2013-03-26 12:58 337 查看
腾讯马拉松,我报的是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

#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <vector>
#include <bitset>
#include <cstdio>
#include <string>
#include <numeric>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
#define exp 1e-8
#define inf 0x7fffffff
#define read freopen("in.txt","r",stdin)
#define write freopen("out.txt","w",stdout)
#define maxn 2005
#define maxe maxn*maxn*2
int mp[maxn][maxn];
char ss[maxn];
int main()
{
//read;
int n,m;
while(~scanf("%d%d",&n,&m)&&(n+m))
{
int x,y;
scanf("%d%d",&x,&y);
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)mp[i][j]=0;
for(int i=0;i<n;i++)
{
scanf("%s",ss);
for(int j=0;j<m;j++)if(ss[j]=='*')mp[i+1][j+1]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
mp[i][j]=mp[i][j]+mp[i-1][j]+mp[i][j-1]-mp[i-1][j-1];
int tt=x*y;
ll ans=0;
for(int i=x;i<=n;i++)
for(int j=y;j<=m;j++)
if(mp[i][j]-mp[i][j-y]-mp[i-x][j]+mp[i-x][j-y]==tt)ans++;
if(x!=y)for(int i=y;i<=n;i++)
for(int j=x;j<=m;j++)
if(mp[i][j]-mp[i][j-x]-mp[i-y][j]+mp[i-y][j-x]==tt)ans++;
printf("%I64d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐