首页 > 学院 > 开发设计 > 正文

【POJ】3274 Gold Balanced Lineup 哈希hash

2019-11-08 03:21:52
字体:
来源:转载
供稿:网友

对于这些英文的题目,我们的首要任务是搞清楚题目的意思。题目大意:

说实话,我起初拿到这题的时候并不认为这题和哈希有半毛钱关系……

好吧,我们还是讲题目吧。(正经脸)

1、我们把依次读入的x转化成一个二进制数c[i],得到一个01矩阵a[n][k-1]。

2、我们可以对a数组进行前缀求和,得到c数组的前缀和数组sum[n][k-1]。

3、我们枚举i和j(i>j),判断sum[i][l]-sum[j][l](0<=l<=k-1)是否等于sum[[i][0]-sum[j][0],若等于,则ans=max(ans,i-j)。注意:是i-j,而不是i-j+1,因为sum数组是前缀和。

以上都是O(n^2)的正常思路,可惜n的最大值为100000,铁定TLE。

接下来我将详细阐述正解:hash

请观察上述解法第3步的判断,若sum[i]-sum[j]=sum[i][0]-sum[j][0],则sum[i][0]-sum[j][0]=sum[i][1]-sum[j][1]=……=sum[i][k-1]-sum[j][k-1]

由上述等式可得:sum[i][1]-sum[i][0]=sum[j][1]-sum[j][0],sum[i][2]-sum[i][0]=sum[j][2]-sum[j][0]……sum[i][k-1]-sum[i][0]=sum[j][k-1]-sum[j][0]

上述等式的变形是这道题的解题关键所在。经过上述对sum数组的操作后,我们可以得到一个新的数组:c[i][j]表示sum[i][j]-sum[i][0]

然后原问题就转化成了求c数组中相同两行的最远距离,设k=hash(c[i]),在枚举h[k]中的所有元素,更新ans。

小提示:记得在更新ans之前在h[0]中加入一个元素:0,即在c数组加上第0行:全都是0的一行。

附上AC代码:

#include <cstdio>#include <vector>#define lyf 233333using namespace std;vector <int> h[lyf+1];int n,m,x,a[100010][31],sum[100010][31],c[100010][31],ans;int abs(int a){	return a>0?a:-a;}int hash(int x){	int ans=0;	for (int i=0; i<=m; ++i)		ans+=c[x][i]*i;	return abs(ans)%lyf;}bool pd(int i,int j){	for (int k=0; k<=m; ++k)		if (c[i][k]!=c[j][k]) return 0;	return 1; }int max(int a,int b){	return a>b?a:b;}int main(void){	scanf("%d%d",&n,&m);--m;	h[0].push_back(0);	for (int i=1; i<=n; ++i){		scanf("%d",&x);		for (int j=0; j<=m; ++j){			a[i][j]=x%2,x/=2;			sum[i][j]=sum[i-1][j]+a[i][j];			c[i][j]=sum[i][j]-sum[i][0];		}		int k=hash(i);		for (int j=0; j<h[k].size(); ++j)			if (pd(i,h[k][j])) ans=max(ans,abs(i-h[k][j]));		h[k].push_back(i);	}	PRintf("%d",ans);	return 0;}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表