这个题看了题解之后才会写的,每头牛最多有k个属性,用给出数字的对应二进制位表示,
0为没有这种属性,1为具有这种属性。要求的是最长的一个牛的序列,使得每种属性出现
的次数相同。参考网上的hash函数 ret = ((ret << 2) + (a[i] >> 4)) ^ (a[i] << 10);
用sum[i][j]表示前i头牛的第j种属性出现的次数。用c[i][j]存储sum[i][j] - sum[i][0]的
值,代表前i头牛第j种属性出现次数与第0种属性出现次数的差值。如果存在i1和i2,使得
c[i1][j] = c[i2][j] 0< j < k, i1到i2这一段就是符合要求的一个解。找到最长的i2 - i1
就是答案。这里理解过来就是在i1到i2所有属性出现次数的增量都相同。
[分析]:以样例为例:
转换成二进制
111
110
111
010
001
100
010
sum[i][j]的值,累加的过程。
111
221
332
342
343
443
453
都减去第0种属性出现的次数和
000
110 i1
110
120
010
110 i2
120
到此可以看出规律, i2 - i1就是所求答案。
/*Accepted 26420 KB 266 ms C++ 1471 B 2012-08-24 14:41:44*/ #include<stdio.h> #include<string.h> #include<stdlib.h> const int MAXN = 100100; const int MAXK = 32; int sum[MAXN][MAXK], c[MAXN][MAXK]; int first[MAXN], next[MAXN], v[MAXN], e; int n, p, ans; void addedge(int x, int y) { next[e] = first[x], v[e] = y; first[x] = e ++; } int hash(int c[]) { int ret = 0, i; for(i = 0; i < p; i ++) ret = ((ret << 2) + (c[i] >> 4)) ^ (c[i] << 10); ret = (ret % MAXN + MAXN) % MAXN; return ret; } void cal() { int i, j, k, a, h; memset(sum, 0, sizeof sum); memset(c, 0, sizeof c); memset(first, -1, sizeof first); e = ans = 0; addedge(hash(c[0]), 0); for(i = 1; i <= n; i ++) { scanf("%d", &a); for(j = 0; j < p; j ++) { sum[i][j] = sum[i - 1][j] + (1 & a); a >>= 1; } for(j = 0; j < p; j ++) { c[i][j] = sum[i][j] - sum[i][0]; } h = hash(c[i]); for(j = first[h]; j != -1; j = next[j]) { bool ok = true; for(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); } } int main() { while(scanf("%d%d", &n, &p) != EOF) { cal(); printf("%d\n", ans); } return 0; }