Gold Balanced Lineup poj3274

来源:互联网 发布:淘宝儿童玩具 编辑:程序博客网 时间:2024/05/01 07:41


   这道题感觉真的很好,做完之后对hash的理解也更加深刻了。自己当时没想到能用hash,后来看了官方解后才恍然大悟,不过真的很难想到这样转化啊奋斗

首先用sum[i][j]表示从第一行到第i行具有特性j的牛的头数,显然若满足 sum[i][t]-sum[j][t]=常数 (1<=t<=k),则从第i+1行到第j行的牛符合题目要求。但如果是这样表示的话,最后还是要枚举任意两行,那么这个处理也就没多大作用了。重点来了,我们可以令c[i][j]=sum[i][j]-sum[i][1](1<=j<=k) ,所以上等式等价于 c[i][t]=c[j][t](1<=t<=k), 这样的话,就可以应用hash了。我的做法是将每一行的c[i][j]值相加,作为其哈希值,若出现两行的hash值相等,再去比较这两行对应的c[i][j]是否都相等。很显然这样处理后,就避免了任意两行都去比较了,因此hash的好处得到了充分的体现!

#include<iostream>#include<cstdio>#include<cstring>#include<vector>using namespace std;vector<int>hash[100001];int sum[100001][31];//sum[i][j]记录从第一行到第i行第j个特性出现的次数int c[100001][31];//c[i][j]=sum[i][j]-sum[i][0]int n,k;void to_bit(int *arr,int num)//十进制转化为二进制{int i=0;while(num){arr[++i]=(num&1);num/=2;}for(i++;i<=k;i++)//不满的位填0arr[i]=0;}int main(){int i,j,num,MAX,bit[31];while(~scanf("%d%d",&n,&k)){for(i=1;i<=n;i++)//读入数据并计算sum[i][j]{scanf("%d",&num);to_bit(bit,num);for(j=1;j<=k;j++)sum[i][j]=sum[i-1][j]+bit[j];}for(i=1;i<=n;i++)//计算c[i][j]for(j=1;j<=k;j++)c[i][j]=sum[i][j]-sum[i][1];for(i=1;i<=n;i++)hash[i].clear();MAX=0;for(i=0;i<=n;i++)//注意要从0开始{//哈希(求和再模n)num=0;for(int j=1;j<=k;j++)num+=c[i][j];if(num<0)num=-num;num%=n;//对于哈希值相等的行,再判断该行对应的各元素是否都相等for(j=0;j<hash[num].size();j++){int t=hash[num][j],x=0;while(x<=k&&c[i][x]==c[t][x])x++;if(x>k&&MAX<(i-t))//第i行和第t行对应相等,说明t+1~i满足题意(这也是为何i从0开始的原因)MAX=i-t;}hash[num].push_back(i);}printf("%d\n",MAX);}return 0;}


 

 

 

原创粉丝点击