您的位置:首页 > 编程语言 > Go语言

POJ_3274_Gold Balanced Lineup_哈希

2015-04-13 19:06 405 查看
今天电工实习焊了一下午电路,已中毒。

题意:

FJ有N ( 1 <= N <= 10 ^ 5 ) 头奶牛,这些奶牛有K ( 1 <= K <= 30)种属性,每头奶牛有可能有其中任意种属性,给出N个数字描述每头奶牛的属性,数字的二进制写法最右第一位代表是否有第一个属性,以此类推。FJ发现一些连续段的奶牛的K个属性总是平衡的,平衡定义为,这一段每个属性的出现次数相等。问最长一段这样的平衡段有多长?

Input
Line 1: Two space-separated integers, N and
K.

Lines 2..N+1: Line i+1 contains a single K-bit integer specifying the features present in cow
i. The least-significant bit of this integer is 1 if the cow exhibits feature #1, and the most-significant bit is 1 if the cow exhibits feature #K.
Output
Line 1: A single integer giving the size of the largest contiguous balanced group of cows.

我们可以用一个数组来描述一头奶牛,题目要求求和,因此求出前缀和数组。

至此,朴素算法O(N^2)枚举区间和判断区间和是否所有元素相等。O(N^2)对此题太大,暴力枚举不可行。

注意到后面的前缀和一定大于前面的前缀和(这是一个用处不大的前提)。

如果我们把每一个前缀和数组每一项同加同减一个数字(不同前缀和加减的数字可以不同),两个区间和做差之后是否所有元素相等的性质不变,因此我们可以让所有前缀和第一项变为同一个数字,其他项加减第一项变化所需的对应数字。这时,如果两个项每一项相等,他们原始数据做差必然满足题目平衡的要求。

这时题目就变成了N个数组找尽可能大的i, j,使得sum[i]==sum[j]了。

这时应当就有不少熟悉的算法来解决了。

我AC的做法是把一个前缀和数组哈希成一个数字,具体哈希方程就是求和。哈希冲突用链表解决,实现的问题是空间比较拮据,由于我不想用STL map来拖慢时间造成可能的TLE,我用数组存储哈希表,这样就要求每个哈希值必须非负,如果在加减前缀和数组时使sum[i][0]=0,那样sum[i]数组里最小的数字可能打倒-MXN,所以令sum[i][0]=N,这样单项sum最大打倒2*MXN,K个项求和,哈希值范围从0到达60*MXN,这个数字在MXN,MXK开得比较紧缩的情况下可以过,一开始我怕过不了,将以上哈希值除以2作为哈希公式,结果超时,但是在搜索时加入了几句删除已搜索过的前缀和的代码,就A了。

这种做法和网上搜到的官方做法较为相近。官方做法是将sum数组转化为sum内部各项减sum[0]之差的C数组,和我的方法所采用的信息实质相同,数学上的来源是sum[j][0]-sum[i][0]=sum[j][[1]-sum[i][1]=...等式的变形。官方哈希貌似是进制哈希,不知道是怎么解决哈希值为负的问题的。

做完此题后我想到了另一种做法,按照我上面的做法走到哈希之前,令每个前缀和数组第一项为0,之后建立一个结构体存储前缀和数组,同时存储该前缀和编号,然后排序结构体,定义小于为前缀和数组字典序小于,之后就O(N)遍历,每个点找附近的点和他的最大编号绝对值差即可。

哈希代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define MXN 100005
#define MXK 35
int n,k;
int feature[MXN][MXK];
int sum[MXN][MXK];
int hash[MXN];
struct hash_node{
int idx;
hash_node* nxt;
hash_node(){nxt=NULL;}
hash_node(int a,hash_node* b){idx=a,nxt=b;}
}node[MXN];
hash_node *(hash_table[60*MXN]);
int cnt;
void init(){
cnt=0;
memset(hash_table,0,sizeof(hash_table));
memset(feature,0,sizeof(feature));
memset(sum,0,sizeof(sum));
}
void decode(int val,int idx){
int now=0;
while(val){
feature[idx][now]=val%2;
val/=2;
++now;
}
}
void add(int value,int index){
hash_node* tem=hash_table[value];
hash_table[value]=node+cnt++;
(hash_table[value])->idx=index;
(hash_table[value])->nxt=tem;
}
void calc_sum(){
int tem=0;
for(int i=0;i<k;++i)	sum[0][i]=n;
hash[0]=n*k;
add(n*k,0);
for(int i=0;i<n;++i){
tem=0;
for(int j=0;j<k;++j){
sum[i+1][j]=sum[i][j]+feature[i][j]-feature[i][0];
tem+=sum[i+1][j];
}
hash[i+1]=tem;
add(tem,i+1);
}
}
int main(){
while(scanf("%d%d",&n,&k)!=EOF){
init();
for(int i=0;i<n;++i){
int tem;
scanf("%d",&tem);
decode(tem,i);
}
calc_sum();
int ans=0;
for(int i=0;i<=n;++i){
hash_node* pre=NULL;
for(hash_node* j=hash_table[hash[i]];j!=NULL;j=j->nxt){
if(j->idx<=i){
if(pre==NULL)	hash_table[hash[i]]=j->nxt;
else	pre->nxt=j->nxt;
continue;
}
pre=j;
bool ok=true;
for(int l=0;l<k;++l)	if(sum[i][l]!=sum[j->idx][l])
ok=false;
if(ok){
int tem=i-j->idx;
if(tem<0)	tem=-tem;
ans=max(ans,tem);
}
}
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: