解题思路
比赛的时候根本没看懂题目,我笑了,笑死了。。。
题目大题:输入一个数,把它转换为2^64后,两个数只有在二进制下仅有三位不同就可以互相匹配,现在n次给数,要求每次给数后输出当前数列中的与最新的数的匹配数。
我们可以把这个数分为四份,每份一个16位的二进制数,则,如果两个数要相互匹配(即恰好只有 3 位不同)就要满足其中一份完全一样。
我们每次新加入一个数就找出前面跟这个数的某一段完全一样的数。可以用邻接表把这样所有有一段一样的数接在一起。然后你就只跟这些数匹配,是的,暴力匹配。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<cmath>
#define ull unsigned long long
using namespace std;
int n,k,ans;
ull a[150010],x[150010],head[800010][5];
struct c{
int x,next;
}e[600010];
void add1(int x,int y){
e[++k]=(c){y,head[x][1]},head[x][1]=k;
}
void add2(int x,int y){
e[++k]=(c){y,head[x][2]},head[x][2]=k;
}
void add3(int x,int y){
e[++k]=(c){y,head[x][3]},head[x][3]=k;
}
void add4(int x,int y){
e[++k]=(c){y,head[x][4]},head[x][4]=k;
}
bool check(int xx,int yy){
int cnt=0;
for(int i=1;i<=64;i++)
if(((x[xx]>>i)&1)^((x[yy]>>i)&1))
cnt++;
return cnt==3;
}
int main(){
freopen("hashing.in","r",stdin);
freopen("hashing.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%llud",&x[i]);
a[0]=0;
ans=0;
int xx=x[i]%(1<<16);
for(int j=head[xx][1];j;j=e[j].next)
a[++a[0]]=e[j].x;
add1(xx,i);
xx=(x[i]>>16)%(1<<16);
for(int j=head[xx][2];j;j=e[j].next)
a[++a[0]]=e[j].x;
add2(xx,i);
xx=(x[i]>>32)%(1<<16);
for(int j=head[xx][3];j;j=e[j].next)
a[++a[0]]=e[j].x;
add3(xx,i);
xx=(x[i]>>48);
for(int j=head[xx][4];j;j=e[j].next)
a[++a[0]]=e[j].x;
add4(xx,i);
sort(a+1,a+a[0]+1);
a[0]=unique(a+1,a+a[0]+1)-a-1;
for(int j=1;j<=a[0];j++)
if(check(i,a[j]))
ans++;
printf("%d\n",ans);
}
}