poj3274

题意:n头牛站一排,每个牛有k个属性,每个属性有两种取值:1或0。(1表示拥有该属性,0表示没有)要求找一个牛的最长连续队伍(子段),这个队伍中拥有每个属性的牛的个数相同。

分析:我们记录一个sum[i][j]数组,记录前i个牛的第j个属性和。我们用我们需要寻找sum中的两行,这两行中所有对应位的差都相等,则这段牛是符合条件的答案之一。所以我们用另一数组,来记录sum中对应行的各个元素之间的差异。我们记录c[i][j] = sum[i][j] - sum[i][0]这样只要c的两行对应相等即可。然后我们就找相隔最远的两个c的相等行即为所求。我们要对c的每行进行hash。hash数组的方法是        ret = ((ret << 2) + (a[i] >> 4)) ^ (a[i] << 10);

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
usingnamespace std;

#define maxn 100005
#define maxk 32

int sum[maxn][maxk], c[maxn][maxk];
int head[maxn], next[maxn], v[maxn], ecount;
int n, p;

void addedge(int a, int b)
{
next[ecount]
= head[a];
head[a]
= ecount;
v[ecount]
= b;
ecount
++;
}

int hash(int c[])
{
int ret =0;
for (int i =0; i < p; i++)
ret
= ((ret <<2) + (c[i] >>4)) ^ (c[i] <<10);
ret
= (ret % maxn + maxn) % maxn;
return ret;
}

void input()
{
memset(sum,
0, sizeof(sum));
memset(c,
0, sizeof(c));
memset(head,
-1, sizeof(head));
scanf(
"%d%d", &n, &p);
ecount
=0;
int ans =0;
addedge(hash(c[
0]), 0);
for (int i =1; i <= n; i++)
{
int a;
scanf(
"%d", &a);
for (int j =0; j < p; j++)
{
sum[i][j]
= sum[i -1][j] + (1& a);
a
>>=1;
}
for (int j =0; j < p; j++)
c[i][j]
= sum[i][j] - sum[i][0];
int h = hash(c[i]);
for (int j = head[h]; j !=-1; j = next[j])
{
int ok =true;
for (int k =0; k < p; k++)
if (c[v[j]][k] != c[i][k])
{
ok
=false;
break;
}
if (ok && ans < i - v[j])
ans
= i - v[j];
}
addedge(h, i);
}
printf(
"%d\n", ans);
}

int main()
{
//freopen("t.txt", "r", stdin);
input();
return0;
}
posted @ 2011-07-01 18:31  金海峰  阅读(1590)  评论(0编辑  收藏  举报