看到题时确实不知道怎么做,看了discuss 和 网上的讲解,也是不明白。。 有时候,可能也是自己的心理原因,遇到问题,第一反应就是放弃,所以才让本不简单的题变得更难,不过后来我想了,越是难题,越需要我们去做,只有将不会的变成会的,才能真正进步,幸好我又坚持了下, 发现也不是太难了,呵呵。。

题意:对于每头奶牛都有一个"feature ID",用一个整数表示,把这个数表示成K位二进制,对应位为1表示具有相应的特征,这样n头奶牛排成一排,求最长的连续区间,使得里面奶牛的全部K个特征个数达到平衡,即:
如果用sum[i][j] 表示前 i 头奶牛的第 j 个特征个数总和,则对于区间[a + 1, b],有
sum[b][1] - sum[a][1] = sum[b][2] - sum[a][2] = sum[b][j] - sum[a][j]   (1<= j <= K)
对表达式做变换得:
sum[b][1] - sum[b][2] = sum[a][1] - sum[a][2]
sum[b][1] - sum[b][j] = sum[a][1] - sum[a][j]   (1<= j <= K)
如果令c[i][j] = sum[i][j] - sum[i][1] (1<= j <= K)
则条件可以转换为:c[a] == c[b]
这样我们就可以在求的 c[i][j] (1<= i <= N, 1 <= j <= K)的基础上,对数组c[i](1 <= i <= N) hash,用开散列法(拉链法)求解即可。
代码
#include<stdio.h>
#include
<string.h>
#include
<iostream>
using namespace std;
#define MAXHASH 99983
#define NN 100003
#define KK 33
int N, K;
int head[MAXHASH], nxt[NN];
int a[NN], c[NN][KK];
int sum[NN][KK];

int hash(int v[]){// hash函数可以随便写,这个是我从网上当的
int h = 0;
int i;
for (i = 1; i <= K; i++){
h
= ((h << 2) + (v[i] >> 4))^(v[i] << 10);
}
h
= h % MAXHASH;
h
= h < 0 ? h + MAXHASH : h;
return h;
}
int main() {
int temp, i, j;
scanf(
"%d%d", &N, &K);
for (i = 1; i <= N; i++){
scanf(
"%d", &a[i]);
}
memset(sum,
0, sizeof(sum));
for (i = 1; i <= N; i++){
temp
= a[i];
for (j = 1; j <= K; j++){
sum[i][j]
= sum[i - 1][j] + temp % 2;
temp
/= 2;
}
}

int ans = 0;

memset(head,
-1, sizeof(head));
for (i = 0; i <= N; i++){ //这里从0开始
for (j = 1; j <= K; j++) c[i][j] = sum[i][j] - sum[i][1];
int h = hash(c[i]);
bool find = 0;
for (int p = head[h]; p != -1; p = nxt[p]){
for (j = 1; j <= K; j++){
if(c[i][j] != c[p][j]) break;
}
if(j > K){
if(i - p > ans) ans = i - p;
find
= 1;
break;
}
}
if(!find){
nxt[i]
= head[h];
head[h]
= i;
}
}
printf(
"%d\n", ans);
return 0;
}

 

这题能看出是hash来做也挺难的,总的感觉是不懂hash 的真正用处,才会想不到解法,这题就是将原有的n^2算法,把其中的n对应到一个hash表中,对应同一个键值的才可能满足答案要求,于是对每个键值里的元素进行n'^2算法这里的n'都已经非常小了,从而降低复杂度。

参考的结题报告

posted on 2010-12-03 09:52  ylfdrib  阅读(1225)  评论(0编辑  收藏  举报