POJ_3274_Gold Balanced Lineup_哈希
来源:互联网 发布:解屏幕锁软件 编辑:程序博客网 时间:2024/05/20 18:03
今天电工实习焊了一下午电路,已中毒。
题意:
FJ有N ( 1 <= N <= 10 ^ 5 ) 头奶牛,这些奶牛有K ( 1 <= K <= 30)种属性,每头奶牛有可能有其中任意种属性,给出N个数字描述每头奶牛的属性,数字的二进制写法最右第一位代表是否有第一个属性,以此类推。FJ发现一些连续段的奶牛的K个属性总是平衡的,平衡定义为,这一段每个属性的出现次数相等。问最长一段这样的平衡段有多长?
Input
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
我们可以用一个数组来描述一头奶牛,题目要求求和,因此求出前缀和数组。
至此,朴素算法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;}
- POJ_3274_Gold Balanced Lineup_哈希
- poj3264_Balanced Lineup_线段树
- 哈希-Gold Balanced Lineup
- (哈希) Gold Balanced lineup (P3274)
- POJ3264_Balanced Lineup_线段树维护最大值和最小值
- POJ3274《Gold Balanced Lineup》方法:哈希
- Gold Balanced Lineup - POJ 3274 哈希
- POJ Gold Balanced Lineup 3274 哈希
- 【POJ】3274 Gold Balanced Lineup 哈希hash
- Poj 3274 Gold Balanced Lineup 【哈希】
- Balanced Lineup
- Balanced Lineup
- Balanced Lineup
- Balanced Partition
- Balanced Number
- poj3264 balanced
- Balanced Lineup
- Balanced Number
- 能让你快速了解Java中的一维数组和二维数组的内存图!!!!!
- NSSortDescriptor排序
- C#treeview选定节点的值
- unicode库
- (二)php的常量和变量
- POJ_3274_Gold Balanced Lineup_哈希
- 历届试题 数字游戏
- Android学习笔记之Intent
- LibSVM格式简介和利用Excel与CSV/XLS格式转换
- 第六周项目5-友元类
- myecplise文件如何转成ecplise文件 第一天 要学会的三洋东西 工作流引擎 搜索引擎 mabatis框架2015 4 24
- 历届试题 回文数字
- 两个向量的夹角(顺时针)
- FragmentTransaction与Fragment生命周期的关系