POJ-3274(hash结构)(Gold Balanced Lineup )

大概意思就是:
数组sum[i][j]表示从第1到第i头cow属性j的出现次数。
所以题目要求等价为:
求满足
sum[i][0]-sum[j][0]=sum[i][1]-sum[j][1]=.....=sum[i][k-1]-sum[j][k-1] (j<i)
中最大的i-j

将上式变换可得到
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]
令C[i][y]=sum[i][y]-sum[i][0] (0<y<k)
初始条件C[0][0~k-1]=0
所以只需求满足C[i][]==C[j][] 中最大的i-j,其中0<=j<i<=n。
C[i][]==C[j][] 即二维数组C[][]第i行与第j行对应列的值相等,
那么原题就转化为求C数组中 相等且相隔最远的两行的距离i-j。 


以样例为例


7 37672142 先把7个十进制特征数转换为二进制,并逆序存放到特征数组feature[ ][ ],得到:


7 -> 1 1 1
6->  0 1 1
7 -> 1 1 1
2->  0 1 0

1-> 1 0 0

4-> 0 0 1
2->  0 1 0


(行数为cow编号,自上而下从1开始;列数为特征编号,自左到右从0开始)

再求sum数组,逐行累加得,sum数组为
1 1 1
1 2 2
2 3 3
2 4 3
3 4 3
3 4 4
3 5 4
再利用C[i][y]=sum[i][y]-sum[i][0]求C数组,即所有列都减去第一列
注意C数组有第0行,为全0

0 0 0

0 1 1

0 1 1
0 2 1
0 1 0
0 1 1
0 2 1
显然第2行与第6行相等,均为011,且距离最远,距离为6-2=4,这就是所求。
但是最大数据有10W个,即10W行,因此不能直接枚举找最大距离,必须用Hash查找相同行,找到相同行再比较最大距离。
注意C数组的值可能为负数,因此生成key值时要注意保证key为非负数。

int N, K;
#define MAX 100005
#define MOD 99991
int maxlen;
int c[MAX][30];
int sum[MAX][30];
int feature[MAX][30];
struct HASH
{
	int index;
	struct HASH * next;
	HASH() { next = NULL; }
} * hash[MOD];
bool cmp(int a, int b)
{
	int i;
	for (i = 0; i < K; ++i)
		if (c[a][i] != c[b][i])
			return false;
	return true;
}
void Hash(int index)
{
	int key = 0;
	int i, j;
	for (i = 0; i < K; ++i) {
		key += c[index][i] * i;
	}
	key = MY_ABS(key) % MOD;
	if (!hash[key]) {
		HASH * tmp = new HASH;
		tmp->index = index;
		hash[key] = tmp;
	} else {
		HASH * tmp = hash[key];
		if (cmp(tmp->index, index)) {
			int d = index - tmp->index;
			maxlen = MY_MAX(maxlen, d);
			return ;
		} else {
			while (tmp->next) {
				if (cmp(tmp->next->index, index)) {
					int d = index - tmp->next->index;
					maxlen = MY_MAX(maxlen, d);
					return ;
				}
				tmp = tmp->next;
			}
			HASH * t = new HASH;
			t->index = index;
			tmp->next = t;
		}
	}
}
int main()
{
	int i, j, k;
	while (scanf("%d%d", &N, &K) == 2) {
		for (i = 0; i < K; ++i) {//初始化第0头牛
			c[0][i] = 0;
			sum[0][i] = 0;
		}
		memset(hash, 0, sizeof(hash));
		maxlen = 0;
		Hash(0);
		for (i = 1; i <= N; ++i) {
			scanf("%d", &k);
			for (j = 0; j < K; ++j) {
				feature[i][j] = k % 2;
				k /= 2;
				sum[i][j] = sum[i - 1][j] + feature[i][j];
				c[i][j] = sum[i][j] - sum[i][0];
			}
			Hash(i);
		}
		printf("%d\n", maxlen);
	}
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值