【POJ】3274 Gold Balanced Lineup 哈希hash

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

【POJ】3274 Gold Balanced Lineup 哈希hash_第1张图片

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

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

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 
#include 
#define lyf 233333
using namespace std;

vector  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

你可能感兴趣的:(POJ,hash,难题)