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)遍历,每个点找附近的点和他的最大编号绝对值差即可。
哈希代码如下:
题意:
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; }
相关文章推荐
- Poj 3274 Gold Balanced Lineup 【哈希】
- POJ Gold Balanced Lineup 3274 哈希
- Gold Balanced Lineup - POJ 3274 哈希
- POJ 3274 Gold Balanced Lineup 哈希
- POJ 3274:Gold Balanced Lineup 做了两个小时的哈希
- POJ 3274:Gold Balanced Lineup 做了两个小时的哈希
- POJ 3274 Gold Balanced Lineup(哈希)
- 【POJ】3274 Gold Balanced Lineup 哈希hash
- POJ 3274 Gold Balanced Lineup(哈希)
- poj_3274 Gold Balanced Lineup(数字哈希)
- poj3274——Gold Balanced Lineup
- POJ_3274 Gold Balanced Lineup 解题报告
- POJ 3274 Gold Balanced Lineup
- POJ 3274 Gold Balanced Lineup(HASH)
- poj 3274 Gold Balanced Lineup
- poj 3274 Gold Balanced Lineup
- POJ 3274 Gold Balanced Lineup
- POJ 刷题系列:3274. Gold Balanced Lineup
- POJ 3274 Gold Balanced Lineup
- POJ 3274 Gold Balanced Lineup (hash)