(纪中)5101. 凡喵识图【暴力??】

57 篇文章 0 订阅

在这里插入图片描述
在这里插入图片描述


解题思路

比赛的时候根本没看懂题目,我笑了,笑死了。。。

题目大题:输入一个数,把它转换为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);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值