POJ_3274_Gold Balanced Lineup_哈希

来源:互联网 发布:解屏幕锁软件 编辑:程序博客网 时间:2024/05/20 18:03

今天电工实习焊了一下午电路,已中毒。


题意:

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



Input

Line 1: Two space-separated integers, N andK.
Lines 2..N+1: Line i+1 contains a single K-bit integer specifying the features present in cowi. 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 35int 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;elsepre->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;}


0 0
原创粉丝点击