bzoj 3820: 虫逢 hash

       假设我们按照某一种随机的规则在两个同源变形虫中取一个数,那么由于有l/2是相同的,因此概率为1/4。如果我们给每一个基因定一个值,然后定义一个变形虫的值就是它l个基因中的最小值,那么两个同源变形虫相同的概率就是1/3;两个不同源为1/l。如果取两个,就分别是1/9和1/l^2=1/n。

       那么每次给每个基因随机定值,这样一次可以得到n/9对,不断操作即可。

AC代码如下:

#include<bits/stdc++.h>
#define N 35005
#define M 4000005
using namespace std;

int n,m,l,tot,pt,cnt,q1[M],q2[M],a[N][135],mrk[M],mch[N];
struct node{ int x,y,z; }b[N];
struct hsh{
	int fst[2010527],pnt[M],nxt[M];
	int ins(int x){
		int y=x%2010527,p;
		for (p=fst[y]; p; p=nxt[p])
			if (pnt[p]==x) return p;
		pnt[++tot]=x; nxt[tot]=fst[y]; fst[y]=tot;
		return tot;
	}
}h;
bool cmp(const node &u,const node &v){
	return u.x<v.x || u.x==v.x && u.y<v.y;
}
bool eql(int x,int y){
	pt++; int i,sum=0;
	for (i=1; i<=l; i++) mrk[a[x][i]]=pt;
	for (i=1; i<=l; i++)
		if (mrk[a[y][i]]==pt) sum++;
	return sum==(l>>1);
}
int solve(){
	int i,j,u,v; cnt=0;
	random_shuffle(q1+1,q1+tot+1); random_shuffle(q2+1,q2+tot+1);
	for (i=1; i<=n; i++) if (!mch[i]){
		b[++cnt].x=q1[a[i][1]];
		b[cnt].y=q2[a[i][1]];
		for (j=2; j<=l; j++){
			b[cnt].x=min(b[cnt].x,q1[a[i][j]]);
			b[cnt].y=min(b[cnt].y,q2[a[i][j]]);
		}
		b[cnt].z=i;
	}
	sort(b+1,b+cnt+1,cmp);
	int ans=0;
	for (i=1; i<=cnt; i=j+1){
		for (j=i; j<cnt && b[j+1].x==b[j].x && b[j+1].y==b[j].y; j++);
		for (u=i; u<j; u++) if (!mch[b[u].z])
			for (v=u+1; v<=j; v++) if (!mch[b[v].z])
				if (eql(b[u].z,b[v].z)){
					mch[b[u].z]=b[v].z;
					mch[b[v].z]=b[u].z;
					ans++; break;
				}
	}
	return ans;
}
int main(){
	srand(20160513);
	scanf("%d%d%d",&n,&m,&l); n<<=1; int i,j,k,x;
	char ch=getchar(); while (ch<'!') ch=getchar();
	for (i=1; i<=n; i++)
		for (j=1; j<=l; j++){
			x=0;
			for (k=0; k<4; k++,ch=getchar())
				x=(x<<7)+(int)ch;
			a[i][j]=h.ins(x);
		}
	for (i=1; i<=tot; i++) q1[i]=q2[i]=i;
	x=n>>1;
	while (x) x-=solve();
	for (i=1; i<=n; i++) printf("%d\n",mch[i]);
	return 0;
}


by lych

2016.5.13

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值