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 >
using namespace 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();
return 0 ;
}

你可能感兴趣的:(poj)