POJ3274Gold Balanced Lineup(哈希)
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 10360 | Accepted: 3086 |
Description
Farmer John's N cows (1 ≤ N ≤ 100,000) share many similarities. In fact, FJ has been able to narrow down the list of features shared by his cows to a list of only K different features (1 ≤ K ≤ 30). For example, cows exhibiting feature #1 might have spots, cows exhibiting feature #2 might prefer C to Pascal, and so on.
FJ has even devised a concise way to describe each cow in terms of its "feature ID", a single K-bit integer whose binary representation tells us the set of features exhibited by the cow. As an example, suppose a cow has feature ID = 13. Since 13 written in binary is 1101, this means our cow exhibits features 1, 3, and 4 (reading right to left), but not feature 2. More generally, we find a 1 in the 2^(i-1) place if a cow exhibits feature i.
Always the sensitive fellow, FJ lined up cows 1..N in a long row and noticed that certain ranges of cows are somewhat "balanced" in terms of the features the exhibit. A contiguous range of cows i..j is balanced if each of the K possible features is exhibited by the same number of cows in the range. FJ is curious as to the size of the largest balanced range of cows. See if you can determine it.
Input
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
Sample Input
7 3 7 6 7 2 1 4 2
Sample Output
4
题目大意就是说n个数,表示n头牛所具有的特性,在化为二进制之后哪一位是1表示具有哪种特性,问最长连续有多少个牛,它们所有每一种特性的和相等,如:
7->1 1 1
6->1 1 0
7->1 1 1
2->0 1 0
1->0 0 1
4->1 0 0
2->0 1 0
这样的话从第3行到第6行共4行的长度,它们3种特性的和都为2
大概意思就是:
数组sum[i][j]表示从第1到第i头cow属性j的出现次数。
所以题目要求等价为:
求满足
sum[i][0]-sum[j][0]=sum[i][1]-sum[j][1]=.....=sum[i][k-1]-sum[j][k-1] (j<i)
中最大的i-j
将上式变换可得到
sum[i][1]-sum[i][0] = sum[j][1]-sum[j][0]
sum[i][2]-sum[i][0] = sum[j][2]-sum[j][0]
......
sum[i][k-1]-sum[i][0] = sum[j][k-1]-sum[j][0]
令C[i][y]=sum[i][y]-sum[i][0] (0<y<k)
初始条件C[0][0~k-1]=0
所以只需求满足C[i][]==C[j][] 中最大的i-j,其中0<=j<i<=n。
C[i][]==C[j][] 即二维数组C[][]第i行与第j行对应列的值相等,
那么原题就转化为求C数组中 相等且相隔最远的两行的距离i-j。
这样的话就只需要对数组c进行哈希,下面是网上借鉴来的哈希函数
inline int hashcode(const int *v) { int s = 0; for(int i=0; i<k; i++) s=((s<<2)+(v[i]>>4))^(v[i]<<10); s = s % M; s = s < 0 ? s + M : s; return s; }
另外,在寻找最长满足条件区间长度的时候,我用了一个数组min_index来存放两行相同时上面一行的下标。最初min_index[i]=i.之后一旦找到一个c[j]=c[i],那么min_index[j]=min_index[i].这样的话最大的i-min_index[i]就是最常去肩长度。
当然,还有更多较好的方法,如用结构体放最长长度,一边插入就可以一边找到最大长度。
下面附上代码:
1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #define mem(a) memset(a,0,sizeof(a)) 5 #define MAX 100005 6 #define maxn 107777 7 8 int hash[maxn+5],next[MAX],c[MAX][32],min_index[MAX]; 9 int n,k; 10 11 int abss(int a)//坑爹的code block,不能直接调用abs 12 { 13 return a>=0?a:-a; 14 } 15 16 bool judge(int a,int b)//判断两行是否相同 17 { 18 int i; 19 for(i=0;i<k;i++) 20 { 21 if(c[a][i]!=c[b][i])return false; 22 } 23 return true; 24 } 25 26 inline int hashcode(const int *v)//哈希函数 27 { 28 int s = 0; 29 for(int i=0; i<k; i++) 30 s=((s<<2)+(v[i]>>4))^(v[i]<<10); 31 s = s % maxn; 32 s = s < 0 ? s + maxn : s; 33 return s; 34 } 35 36 bool all_0(int index)//判断这一行是不是全部为0, 37 //是的话那么它与他之前的所有行组合起来可以满足条件 38 { 39 int i; 40 for(i=0;i<k;i++) 41 { 42 if(c[index][i]!=0)return false; 43 } 44 return true; 45 } 46 47 void insert(int index)//插入第index行的c[index] 48 { 49 int h=hashcode(c[index]); 50 if(!h)//这一行里面全是 0 51 { 52 if(all_0(index)){ 53 min_index[index]=0; 54 return ; 55 } 56 } 57 int u=hash[h]; 58 if(!u) 59 { 60 min_index[index]=index; 61 hash[h]=index; 62 return; 63 } 64 while(u) 65 { 66 if(judge(index,u))//如果找到一行与这行相同,就把这条链最小下标传过去 67 { 68 min_index[index]=min_index[u]; 69 return; 70 } 71 u=next[u]; 72 } 73 min_index[index]=index; 74 next[index]=hash[h]; 75 hash[h]=index; 76 } 77 78 int main() 79 { 80 // freopen("in.txt","r",stdin); 81 // freopen("out1.txt","w",stdout); 82 while(~scanf("%d%d",&n,&k)) 83 { 84 mem(hash); 85 mem(next); 86 mem(min_index); 87 mem(c); 88 89 int sum[32]={0},i,j,num; 90 for(i=1;i<=n;i++) 91 { 92 scanf("%d",&num); 93 for(j=0;j<k;j++) 94 { 95 sum[j]+=( ( (1<<j)&(num) )?1:0 ); 96 c[i][j]=sum[j]-sum[0]; 97 } 98 insert(i); 99 } 100 int max=0; 101 for(i=1;i<=n;i++) 102 { 103 max=max>(i-min_index[i])?max:(i-min_index[i]); 104 } 105 printf("%d\n",max); 106 } 107 return 0; 108 }