pku 3274 Gold Balanced Lineup 哈希处理

http://poj.org/problem?id=3274

看到这个题的时候直接给理解错了,以为求存在第k个属性,的牛的个数,直接谢了个排序+二分查找样例过了一交WA了。。心情很郁闷。。自己完全把题意理解错了。

题意是求满足i到j 的差值最大且i到j牛的前k个属性每种属性求和,并且和要相等。求出最大的j - i;

sum[i][j] 表示从第一头牛到第i头牛拥有j属性的牛的个数,则根据题意有,如果i  -> j 最大则有

sum[j][0] - sum[i][0] =  sum[j][1] - sum[i][1] = sum[j][2] - sum[i][2] = .......... = sum[j][k -1] - sum[i][k - 1];

==> sum[i][1] - s[i][0] = sum[j][1] - sum[j][0];

       sum[i][2] - sum[i][0] = sum[j][2] - sum[j][0]

..........

所以有过程:

给出SAMPLE
7 3
7
6
7
2
1
4
2
先转化成二进制:
1 1 1
1 1 0
1 1 1
0 1 0
0 0 1
1 0 0
0 1 0
然后在列上进行累加:
1 1 1
2 2 1<----
3 3 2
3 4 2
3 4 3
4 4 3<----
4 5 3
上面这两步转化还好想。答案是4,是因为两个箭头所指的行列上的差相等。
然后在行上,所有值减去最右边的数:
0 0 0
1 1 0<----
1 1 0
1 2 0
0 1 0
1 1 0<----
1 2 0

然后利用哈希,判断相等且距离最远的。。

View Code
#include <cstdio>
#include <cstring>
#include <iostream>
#define maxn 1000007
#define N 32
using namespace std;

struct node
{
int num;
node *next;
}*hash[maxn + 12],H[maxn];

int n,k,pos;
int sum[maxn][N],c[maxn][N];
int isok(int x,int y)
{
int i;
for (i = 0; i < k; ++i)
{
if (c[x][i] != c[y][i])
break;
}
if (i == k) return y -x;
else return -1;
}
int main()
{
int i,j,a;
int Max = 0;
pos = 0;
memset(hash,0,sizeof(hash));
node *tt = &H[pos++];//这里是个陷阱,要考虑到hash之后的s可能是0,discuss的数据给的提示
tt->num = 0;
tt->next = hash[0];
hash[0] = tt;

scanf("%d %d",&n,&k);
//初始化
for (i = 0; i <= n; ++i)
{
for (j = 0; j < N; ++j)
{
c[i][j] = sum[i][j] = 0;
}
}

for (i = 1; i <= n; ++i)
{
scanf("%d",&a);
for (j = 0; j < k; ++j)
{
sum[i][j] += sum[i - 1][j];
sum[i][j] += a&1;
a = a>>1;
}
int tmp = sum[i][0];
int s = 0;
for (j = 1; j < k; ++j)
{
c[i][j] = sum[i][j] - tmp;
s += c[i][j];
}
s %= maxn;
if (s < 0) s = -s;
node *t; bool flag = false;
for (t = hash[s]; t != NULL; t = t->next)
{
int len = isok(t->num,i);
if (len >= 0)
{
flag = true;
Max = max(Max,len);
}
}
if (!flag)
{
node *q;
q = &H[pos++];
q->num = i;
q->next = hash[s];
hash[s] = q;
}
}
printf("%d\n",Max);
return 0;
}



你可能感兴趣的:(pku)