POJ3274 -Gold Balanced Lineup- HASH+前缀和

http://poj.org/problem?id=3274

题意,给出n,k,k表示接下来的数 用k位二进制表示,

给出n个数,  

求出 最长的一个区间,满足:  该区间整体上,二进制下的每一位(1到k)上 “1”的个数之和 都相等。

 

思路:  首先是先把n个数都转成一个 【n】【k】的01数组,然后怎么找这个区间【i,j】呢?   

sum[i][x] 表示 从1到第i头牛时,一共在x位一共有多少个1

因为要求这个区间【i,j】满足   sum[i][0]-sum[j][0] = sum[i][1]=sum[j][1] =......=sum[i][k]=sum[j][k];

即,从i到j,每一位的增量相等,

将上式左右交换一下可得:

sum[i][1]-sum[i][0]=sum[j][1]-sum[j][0] 

....................

sum[i][k]-sum[i][0] =sum[j][k]-sum[j][0]


设CC[x][k]=sum[i][k]-sum[i][0]

显然,等号左边就是  第i头牛时, 把它的sum数组的每一位减去 第0位得到的一个数组CC[i]

如果cc[i] 的每一位 等于cc[j],那么就会符合 从第i到第j条牛之间   每一位的增量相等.


那么我们预处理得到cc数组之后,直接把这个cc[i]hash成一个 数, 一会排个序,判断hash值相同的 数 相差最远的便是答案


trick,  这样得到的是 cc[j]-cc[i]一定会是 【每一位增量相等】,那么max长度就是j-i, 但是如果存在 cc[i]这个节点本身就是 每一位 均等时, (也就是i的每一位都是1 或0) 此时长度应为  j-i +1 

所以只在放多 一个 每一位全是0的节点即可



<span style="font-size:14px;">#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
typedef unsigned __int64 ull;
ull p=239; 
__int64 tm[100005];
__int64 single[100005][35]; 
__int64 sum[100005][35];
struct node
{
	ull ss;
	__int64 pos;
	node(){}
};
node ss[100005];
__int64 cmp(  node a,  node b)  
{ 
	if (a.ss!=b.ss)
	return a.ss<b.ss;
 	else  
		return a.pos<b.pos;
}
int main()
{
	ull n,i,j,k; 
scanf("%I64d%I64d",&n,&k);
	ull tmp;
	for (i=0;i<k;i++)
		single[1][i]=0;
	for (i=2;i<=n+1;i++)
	{
		scanf("%I64d",&tm[i]); 
		ull times=k,tmp=tm[i];
		while(times--)
		{
			single[i][times]=tmp%2;		//求每一位
			tmp>>=1;
		}
	}
	for (i=1;i<=n+1;i++)
	{
		for (j=0;j<k;j++)
		{
			sum[i][j]=single[i][j]+sum[i-1][j];		//前缀和
		}
	}
	
	for (i=1;i<=n+1;i++)
	{
		ull tmp=0;
		for (j=0;j<k;j++)
		{
			sum[i][j]-=sum[i][k-1];			//减去最右边
			tmp=tmp*p+sum[i][j];		//拉链法求hash值
		}
		ss[i].ss=tmp;		//hash值
		ss[i].pos=i;		//位置
	}
	sort(ss+1,ss+n+1+1,cmp); 
	ull maxx=0;
	for (i=1;i<=n+1;i++)
	{
		ull tmpi=i;
		while (ss[i].ss==ss[i+1].ss&&i<=n )		//选择 相同hash值,距离最远的2个数
			i++;
			if (ss[i].pos-ss[tmpi].pos>maxx)	//更新max
				maxx=ss[i].pos-ss[tmpi].pos;
		
	}

	printf("%I64d\n",maxx);

	
	
	
	
	return 0;
	
}
</span>



你可能感兴趣的:(POJ3274 -Gold Balanced Lineup- HASH+前缀和)