poj3274

来源:互联网 发布:逆袭网络剧第2集 编辑:程序博客网 时间:2024/05/01 11:58

     这道题目的难点在于问题的转化,题目给出n个k bite位的数据,设平衡群为从i到j的数据,这些数据满足如下条件:k个特征在这些数据中出现的次数相同。注意是从i到j的连续的数字,不能有间断。而题目要求出平衡群的最大长度(即平衡群中数子的个数)这个题目朴素的算法就是枚举。将所有在1/2×n^2种可能分别试探,比较求出最大的长度。不用说,铁定超时。既然是哈希题目就要分析如何建立哈希表,如何根据建立的哈希表有效的查找解决问题。而这到题目难就难在如何怎么与哈希表搭上边,当这点解决了,那么一切就都顺利了。下面分析题目:我们设sum[i][j]表示从第一个数字到第i个数字中第j个属性出现的次数。那么平衡群就是满足如下条件的数字串:

sum[ i ][1]-sum[ j-1 ][1]=sum[ i ][ 2] -sum[ j-1 ][ 2] =。。。=sum[i][k]-sum[j-1][k].

这里1<=j<=i<=n,sum[0][y] (y从1到k都为0),只要i,j满足上述等式,那么从j到i的数字串就是平衡群。而题目要求的就是i-j+1的最大值.

对上式进行转化为:

sum[i][2]-sum[i][1]=sum[j-1][2]-sum[j-1][1];

sum[i][3]-sum[i][1]=sum[j-1][3]-sum[j-1][1];

sum[i][k]-sum[i][1]=sum[j-1][k]-sum[j-1][1];

令c[i][y] 表示sum[i][2]-sum[i][1],sum[i][3]-sum[i][1],。。。,sum[i][k]-sum[i][1]

0<=i<=n

只要c[j][y]=c[i][y],0<=j<=i<=n,那么从j+1到i的数字串就是平衡群,它们的长度就是i-j了,题目要求的就是最大的i-j。

这样现在要做的就是判断n+1个c[i](0<=i<=n)中相等的c[i]之间的最大距离。

这里就开始出现哈希的影子了。如果采用朴素的枚举算法枚举所有可能相等的情况,然后求最大距离,时间复杂度为0(n^2),一样超时。所以就想到用哈希查找了。将c[i]各值之和的绝对值作为第i个数字的key值,哈希表的长度取10×n内的最大素数。这样能有效解决冲突。采用链地址法解决冲突。注意这里采用尾插法插入相同哈希位置的节点。因为按照顶点的先后次序插入到哈希表中,这样的话当哈希表位置存在并进行相等比较时,只需要比较第一个相等的c[i],不需要比较后续相等的了(注意分析为什么,这样有利于程序优化,不需要比较一些不必要的操作)。

这里还需要注意几个问题:

1)由于c[i]各值之和可能为负值,故取其绝对值作为key

2) 注意理解上述分析中为什么要保留i=0的情况,以及sum[0][y]的初始化

3)注意分析哈希表头插法与尾插法的不同点,我最开始写的就是头插法,后来发现还可以优化,就换成尾插法了,效率会大大提高

4)注意当k值为1的情况,该情况下,很明显:最大长度即为n

下面是代码:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#define Max 999983#define Range 100010struct Node{int index;int record[40];struct Node *next;}node[Max];bool flag[Max];int sum[Range][40];int c[40];int n,k;__int64 Input;int result=0;void Hash(int pivot,int key,int *p){int tkey=key%Max;if(!flag[tkey]){flag[tkey]=1;node[tkey].index=pivot;for(int i=2;i<=k;i++)node[tkey].record[i]=p[i];node[tkey].next=NULL;}else{struct Node *dir=&node[tkey];bool trag=0;for( ;dir->next!=NULL;dir=dir->next){int i;if(trag)continue;for(i=2;i<=k;i++)if(p[i]!=dir->record[i])break;if(i==k+1){if(pivot-dir->index>result){trag=1;result=pivot-dir->index;//printf("====%d====\n",result);}}}if(!trag){int i;for(i=2;i<=k;i++)    if(p[i]!=dir->record[i])break;if(i==k+1){if(pivot-dir->index>result)result=pivot-dir->index;}}    struct  Node *temp=(struct Node*)malloc(sizeof(struct Node));temp->index=pivot;for(int i=2;i<=k;i++)temp->record[i]=p[i];dir->next=temp;temp->next=NULL;}}int main(){scanf("%d%d",&n,&k);if(k==1){int temp;for(int i=1;i<=n;i++)scanf("%d",&temp);printf("%d\n",n);}else{memset(flag,0,sizeof(flag));memset(sum[0],0,sizeof(sum[0]));Hash(0,0,sum[0]);for(int i=1;i<=n;i++){scanf("%I64d",&Input);    for(int j=1;j<=k;j++){sum[i][j]=sum[i-1][j]+Input%2;Input/=2;}int count=0;for(int s=2;s<=k;s++){c[s]=sum[i][s]-sum[i][1];count+=c[s];}count=abs(count);Hash(i,count,c);}printf("%d\n",result);}return 0;}    


 

0 0
原创粉丝点击