Gold Balanced Lineup poj3274


   这道题感觉真的很好,做完之后对hash的理解也更加深刻了。自己当时没想到能用hash,后来看了官方解后才恍然大悟,不过真的很难想到这样转化啊

首先用sum[i][j]表示从第一行到第i行具有特性j的牛的头数,显然若满足 sum[i][t]-sum[j][t]=常数 (1<=t<=k),则从第i+1行到第j行的牛符合题目要求。但如果是这样表示的话,最后还是要枚举任意两行,那么这个处理也就没多大作用了。重点来了,我们可以令c[i][j]=sum[i][j]-sum[i][1](1<=j<=k) ,所以上等式等价于 c[i][t]=c[j][t](1<=t<=k), 这样的话,就可以应用hash了。我的做法是将每一行的c[i][j]值相加,作为其哈希值,若出现两行的hash值相等,再去比较这两行对应的c[i][j]是否都相等。很显然这样处理后,就避免了任意两行都去比较了,因此hash的好处得到了充分的体现!

#include
#include
#include
#include

using namespace std;
vectorhash[100001];
int sum[100001][31];//sum[i][j]记录从第一行到第i行第j个特性出现的次数
int c[100001][31];//c[i][j]=sum[i][j]-sum[i][0]
int n,k;

void to_bit(int *arr,int num)//十进制转化为二进制
{
	int i=0;
	while(num)
	{
		arr[++i]=(num&1);
		num/=2;
	}
	for(i++;i<=k;i++)//不满的位填0
		arr[i]=0;
}

int main()
{
	int i,j,num,MAX,bit[31];
	while(~scanf("%d%d",&n,&k))
	{
		for(i=1;i<=n;i++)//读入数据并计算sum[i][j]
		{
			scanf("%d",&num);
			to_bit(bit,num);
			for(j=1;j<=k;j++)
				sum[i][j]=sum[i-1][j]+bit[j];
		}
		for(i=1;i<=n;i++)//计算c[i][j]
			for(j=1;j<=k;j++)
				c[i][j]=sum[i][j]-sum[i][1];
		for(i=1;i<=n;i++)
			hash[i].clear();
		MAX=0;
		for(i=0;i<=n;i++)//注意要从0开始
		{
			//哈希(求和再模n)
			num=0;
			for(int j=1;j<=k;j++)
				num+=c[i][j];
			if(num<0)
				num=-num;
			num%=n;
			//对于哈希值相等的行,再判断该行对应的各元素是否都相等
			for(j=0;jk&&MAX<(i-t))//第i行和第t行对应相等,说明t+1~i满足题意(这也是为何i从0开始的原因)
					MAX=i-t;
			}
			hash[num].push_back(i);
		}
		printf("%d\n",MAX);
	}
	return 0;
}


 

 

 

你可能感兴趣的:(Hash)