zoukankan      html  css  js  c++  java
  • 【洛谷P7738】量子通信

    题目

    题目链接:https://www.luogu.com.cn/problem/P7738
    小 Z 正在自学量子计算机相关知识,最近他在研究量子通信章节,并遇到了一个有趣的问题。在该问题中,Alice 和 Bob 正在进行量子通信,它们的通信语言是一个大小为 (n) 的字典 (S),在该字典中,每一个单词 (s_i)(1 le i le n))都可以用一个 (oldsymbol{256}) 位的 (oldsymbol{01}) 来表示。在本题中 (s_i) 可以通过调用函数 gen 来生成,选手可以在题目目录下的 gen.cpp 中查看,该函数的参数 na1a2 将由输入数据给出。
    Alice 和 Bob 接下来要进行 (m) 次通信,每次通信由 Alice 向 Bob 传输恰好一个字典中的单词。然而,两人使用的通信信道并不可靠,会受到噪音的干扰。更具体地,对于第 (i) 次传输,记 Alice 传输的原单词为 (x_i),该 (01) 串会受噪音干扰而翻转最多 (oldsymbol{k_i}) 。换句话说,记 Bob 这次收到的 (01) 串为 (y_i),它与 (x_i) 相比,可能有最多 (k_i) 位是不同的,并且 (y_i) 可能不在字典 (S) 中出现。
    与此同时,Bob 得知坏人 Eve 也潜入了两人的通信信道,并准备干扰两人的通信。他的干扰方式是将 Bob 收到的 (01) 串变为任意的 (256)(01) 串,并且这个串可能不在字典 (S) 中出现。Eve 非常狡猾,他不一定会对每次通信都进行干扰。
    现在 Bob 找来了你帮忙,对于接下来的每次通信,你需要根据 Bob 最终收到的 (01) 串以及这次通信的噪音干扰阈值 (k_i)(0 le k_i le 15)),判断这次通信是否有可能没有受到 Eve 的干扰(即 Bob 收到的 (01) 串可以由字典中的某个单词翻转至多 (k_i) 位后得到)。本次通信如果有可能没受到 Eve 干扰,请你输出 (1),否则输出 (0)。Bob 很信任你的能力,所以你需要在线地回答结果,具体要求见输入格式
    为了降低读入用时, Bob 收到的串将用长度为 (oldsymbol{64}) (oldsymbol{16}) 进制串给出,(16) 进制串中包含数字字符 ( exttt{0} sim exttt{9}) 与大写英文字母 ( exttt{A} sim exttt{F}),其中字符 ( exttt{A} sim exttt{F}) 依次表示数值 (10 sim 15)
    (16) 进制串可以逐位转化为 (01) 串,例如:5 对应 0101A 对应 1010C 对应 1100
    (nleq 4 imes 10^5,mleq 1.2 imes 10^5,kleq 15)

    思路

    这题和 GDOI2017 Day2 T2 简直完全不一样呢。
    (256) 位的二进制数,而 (kleq 15)。也就是说,如果两个二进制串汉明距离不超过 (k),把这两个长度为 (256) 的串分成 (16) 个长度为 (16) 的串,至少会有一段完全相同。
    而这 (n) 个串是可以看作完全随机的。随机 (n) 个长度为 (16) 的二进制串,与给定二进制串一致的期望个数为 (frac{n}{2^{16}}< 7)
    我们把这 (n) 个串都分成 (16) 份,记 (nxt[i][j]) 表示上一个和串 (i) 的第 (j) 段完全相同的是哪一个串。
    然后对于每一次询问,暴力枚举每一段,再枚举这一段完全相同的串尝试匹配。期望下匹配的次数是 (6 imes 16=96) 次。每次直接 lowbit 判断两个二进制数不同的位数即可。
    时间复杂度 (O(256n+1440m))。这个上界特别松,并且数据随机。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    
    const int N=400010;
    int n,m,k,cnt,lastans,vis[N],nxt[N][16],a[N][16],b[16],last[16][1<<16];
    bool s[N][256];
    ull a1,a2;
    char t[100];
    
    ull myRand(ull &k1, ull &k2) {
        ull k3 = k1, k4 = k2;
        k1 = k4;
        k3 ^= (k3 << 23);
        k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26);
        return k2 + k4;
    }
    
    void gen(int n, ull a1, ull a2) {
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < 256; j++)
                s[i][j] = (myRand(a1, a2) & (1ull << 32)) ? 1 : 0;
    }
    
    void check(ull x)
    {
    	for (;x && cnt<=k;cnt++)
    		x-=x&(x^(x-1ULL));
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	scanf("%llu%llu",&a1,&a2);
    	gen(n,a1,a2);
    	for (int i=1;i<=n;i++)
    	{
    		for (int j=0;j<256;j++)
    			a[i][j/16]=(a[i][j/16]<<1)|s[i][j];
    		for (int j=0;j<16;j++)
    			nxt[i][j]=last[j][a[i][j]],last[j][a[i][j]]=i;
    	}
    	while (m--)
    	{
    		scanf("%s%d",t,&k);
    		memset(b,0,sizeof(b));
    		for (int i=0,x;i<64;i++)
    		{
    			if (isdigit(t[i])) x=t[i]-48;
    				else x=t[i]-'A'+10;
    			if (lastans) x^=15;
    			b[i/4]=(b[i/4]<<4)|x;
    		}
    		cnt=114514;
    		for (int i=0;i<16 && cnt>k;i++)
    			for (int j=last[i][b[i]];j;j=nxt[j][i])
    				if (vis[j]!=m+1)
    				{
    					vis[j]=m+1; cnt=0;
    					for (int l=0;l<16 && cnt<=k;l++) check(a[j][l]^b[l]);
    					if (cnt<=k) break;
    				}
    		lastans=(cnt<=k);
    		putchar(lastans+48); putchar(10);
    	}
    	return 0;
    }
    
  • 相关阅读:
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    《算法竞赛入门经典》 例题35 生成元 (Digit Generator, ACM ICPC Seoul 2005,UVa)
    SVN分支
    SVN分支
    SVN 版本回退
    SVN 版本回退
    如何在excel中取消合并单元格后内容自动填充?
    如何在excel中取消合并单元格后内容自动填充?
    如何让自己像打王者荣耀一样发了疯、拼了命的学习?
  • 原文地址:https://www.cnblogs.com/stoorz/p/15071798.html
Copyright © 2011-2022 走看看