Gold Balanced Lineup POJ - 3274

原题链接

考察:hash+前缀和

做完这道题感觉终于懂一点hash了,散列表hash是将值存储在映射的键里,会有不同值映射到相同键,因此必须要处理冲突

这道题牛二进制的前缀和会根据ash函数映射到相同键,这些前缀和有些和答案要求根本不符,所以我们必须筛掉那些不符合的键,也就是说这道题我们不能仅仅存储牛的前缀和映射,因为有和答案不符的会映射到相同键,再存储相同键的时候,我们必须再在相同键里看牛的每一位前缀和是否相同,相同的才是答案

借鉴大佬的思路:

        luogu题解的分析比一些csdn的题解写详细多了....建议看luogu的题解.总之需要牛的每一位属性值区间内个数相同,我们必须想到前缀和思想,每一位的前缀和之差相同就是个数增长相同.想到这和上面那些基本就可以做出来了

注意返回的键值不能为负

涉及前缀和一定要考虑边界0

这道题直接存储下标,这样就不用结构体记录id

用开放地址法就是相等的时候要判断cnt是否相同

 1 #include <iostream>
 2 #include <map>
 3 #include <vector>
 4 using namespace std;
 5 const int N = 100007;
 6 int ans,n,k;//hash 会WA的原因,不同的值会映射到相同的键,必须减少冲突 
 7 int cnt[N][32],h[N];
 8 vector<int> v[N];
 9 int gethash(int i)
10 {
11     int tmp = 0;
12     for(int j=1;j<=k;j++)
13         tmp = tmp*2+cnt[i][j],tmp%=N;
14     return abs(tmp)%N;
15 }
16 bool same(int i,int j)
17 {
18     for(int x=1;x<=k;x++){
19         if(cnt[i][x]!=cnt[j][x]) return false;
20     }
21     return true;
22 }
23 int main()
24 {
25     scanf("%d%d",&n,&k);
26     for(int i=1;i<=n;i++){
27         int x;
28         scanf("%d",&x);
29         for(int j=1;j<=k;j++) cnt[i][j]=((x>>(j-1))&1)+cnt[i-1][j];    
30     }
31     for(int i=0;i<=n;i++){
32         for(int j=k;j>=1;j--) cnt[i][j]-=cnt[i][1];
33         int id = gethash(i);//得到第i头牛的属性和对于哈希值 
34     //    printf("id==%d\n",id);
35         v[id].push_back(i);//得到i头牛对应属性 
36     }
37     for(int i=0;i<N;i++){
38         if(v[i].size()<2) continue;
39         for(int j=0;j<v[i].size();j++){
40             for(int p=j+1;p<v[i].size();p++){
41                 if(same(v[i][j],v[i][p])) ans = max(ans,abs(v[i][j]-v[i][p]));
42             }
43         }
44     }
45     printf("%d\n",ans);
46     return 0;
47 } 

 

posted @ 2021-01-07 12:25  acmloser  阅读(62)  评论(0编辑  收藏  举报