[NOI2021]量子通信

Posted Tan_tan_tann

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2021]量子通信相关的知识,希望对你有一定的参考价值。

量子通信

题解

对于比较两个数之间的翻转位数差,我们可以直接通过对其进行异或得到。
但很明显,如果我们直接暴力查询明显是不可取的,即使你要压位也不免会进行 O ( n m ) O\\left(nm\\right) O(nm)次比较,我们的首要任务是如何减少比较的次数。

通过观察出题人的数据生成代码,我们可以猜测 出题人应该不会丧心病狂到去找参数卡字典,也就是说, 字典是随机的。
对于,随机的字典,我们考虑如何才能快速进行判断。
由于 k ⩽ 15 k\\leqslant 15 k15,我们可以相当将原来 256 256 256位的数分成 16 16 16块,很明显,对于两个反转不超过 15 15 15位的数,他们至少有一块的值是相同的。
而我们分成 16 16 16个块,相当于压 16 16 16位,在随机的字典中,每一个块有同样的块相同的数的期望个数为 n 2 16 \\frac{n}{2^{16}} 216n 16 16 16个块也就是 16 n 2 16 = n 2 12 ≈ 97.66 \\frac{16n}{2^{16}}=\\frac{n}{2^{12}}\\approx97.66 21616n=212n97.66
这个数如果我们暴力比较是否相同的话是挺合适的。
所以我们可以像前向星一样指针的形式记录下来每个块内为某个数的数有哪些,就比较这些数与我们询问的数之间的差值是否小于 k k k

至于输入的数的压位,注意一下输入的数的位数是反的, A A A 1010 1010 1010不是 0101 0101 0101就可以了。压位其实还挺快的。
不过说实话,它的强制在线基本没什么用。大概只是给point 16-18的随机输入准备的吧,可以让你离线的常数大点。
时间复杂度 O ( α ( n + ω m ) ) O\\left(\\alpha(n+\\omega m)\\right) O(α(n+ωm))
实在不放心可以再把块的枚举顺序随机化一下,虽然并没有多大的用。

源码

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long ull;
const int mo=998244353;
const int jzm=2333;
const int lim=10000000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-9;
typedef pair<LL,LL> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;}return t;}
typedef unsigned long long ull;
const int N=400000;
int s[N+1][30],bit[(1<<16)+5],a[30],id[30];
int head[(1<<16)+5][16],nxt[N][16];
char str[70];
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>>4]|=((myRand(a1,a2)&(1ull<<32))?1:0)*(1<<(15-j%16));
}
int n,m;ull a1,a2;
int turn(char x){if('0'<=x&&x<='9')return x-'0';return x-'A'+10;} 
signed main(){
	//freopen("qi.in","r",stdin);
	//freopen("qi.out","w",stdout);
	srand(114514);read(n);read(m);read(a1);read(a2);gen(n,a1,a2);
	for(int i=1;i<(1<<16);++i)bit[i]=bit[i>>1]+(i&1);int lastans=0;
	//for(int i=0;i<16;++i)id[i]=i;random_shuffle(id,id+16);
	for(int i=1;i<=n;++i)for(int j=0;j<16;++j)
		nxt[i][j]=head[s[i][j]][j],head[s[i][j]][j]=i;
	for(int i=1;i<=m;++i){
		scanf("\\n%s",str);int K=0;read(K);bool flag=0;
		for(int j=0;j<16;++j)a[j]=0;
		for(int j=0;j<64;++j)a[j>>2]+=(turn(str[j])<<((3-j%4)<<2));
		for(int j=0;j<16;++j)if(lastans)a[j]^=((1<<16)-1);
		for(int j=15;j>=0&&!flag;--j)
			for(int k=head[a[j]][j];k;k=nxt[k][j]){
				int tmp=0;for(int l=0;l<16&&tmp<=K;++l)tmp+=bit[a[l]^s[k][l]];
				if(tmp<=K){lastans=1;flag=1;break;}
			}
		if(!flag)lastans=0;printf("%d\\n",lastans);
	}
	return 0;
}

谢谢!!!

以上是关于[NOI2021]量子通信的主要内容,如果未能解决你的问题,请参考以下文章

国盾量子等参与中国量子通信行业首批标准编制 量子通信商用再加速

国盾量子等参与中国量子通信行业首批标准编制 量子通信商用再加速

国盾量子等参与中国量子通信行业首批标准编制 量子通信商用再加速

BottomSheetDialogFragment 如何与其宿主片段通信?

带 Hilt 的活动片段通信

与 viewpager 内的片段的父片段通信