1 条题解

  • 0
    @ 2025-8-24 22:32:39

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:32:39,当前版本为作者最后更新于2021-07-28 16:14:48,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目传送门。

    题意简述:给出 nn256256 位二进制数(随机生成)aia_i。对于 mm 个询问,每次给出一个 256256 位二进制数 xx 和一个十进制数 kk,求是否存在 aia_i 使得 x,aix,a_i 不同位数个数不大于 kk

    注意到这个 k15k\leq 15,一定是本题的突破点。再根据 162=25616^2=256 与抽屉原理,不难想到将 256256 位的二进制数看成 1616 位的 6553665536 进制数。这样一来,如果 xxaia_i 在二进制下不同位数个数不大于 1515,那么它们在 6553665536 进制下必定至少有一位完全相等。这是显然的。

    因此,我们可以枚举 xx6553665536 进制下的 1616 位,并检查与 xx 在该位相等的所有 aia_i 是否符合要求。由于数据随机生成,所以某一位为某个数的 aia_i 的期望个数为 n655367\dfrac{n}{65536}\approx 7。所以对于每一位,我们期望检查 77aia_i 是否符合要求。而满足在 6553665536 进制下第 bb 位为 ccaia_i 的所有 ii 可以开 vector 存储。

    检查方法很简单:要求出 6553665536 进制数 x,yx,y 在二进制下有多少位不同,只需要预处理出 0655350\sim 65535 在二进制下 11 的个数,然后枚举 x,yx,y 的每一位(一共 1616 位),加上 它们在这一位的值的异或和 在二进制下 11 的个数即可。

    极限数据下空间复杂度为 16n16n期望时间复杂度为 m×16×7×162×108m\times 16\times 7\times 16\approx 2\times 10^8,其中 mm 表示询问个数,第一个 1616 表示枚举的 1616 位,77 表示与 xx 在枚举的某一位的值相等的 aia_i 的期望个数,而第二个 1616 表示检查的复杂度。

    为了卡常,可以进行以下优化:

    • vector 换成链式前向星。
    • 使用 fread
    • 检查时使用指针而不是数组。
    • 如果已经不符合条件,退出检查(不加这个优化会 T 掉几个点)。
    #include <bits/stdc++.h>
    using namespace std;
    
    #define gc getchar()
    #define mem(x,v) memset(x,v,sizeof(x))
    
    typedef unsigned long long ull;
    typedef unsigned short us;
    
    namespace IO{
    	char buf[1<<23],*p1=buf,*p2=buf;
    	#ifdef __WIN32
    		#define gc getchar()
    	#else
    		#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<22,stdin),p1==p2)?EOF:*p1++)
    	#endif
    	inline int read(){
    		int x=0;char s=gc;
    		while(!isdigit(s))s=gc;
    		while(isdigit(s))x=(x<<1)+(x<<3)+(s-'0'),s=gc;
    		return x;
    	}
    } using namespace IO;
    
    const int N=400000+5;
    const int W=65536;
    bool s[N][256],q[256];
    
    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=0;i<n;i++)
            for(int j=0;j<256;j++)
                s[i][j]=(myRand(a1,a2)&(1ull<<32))?1:0;
    }
    
    struct EDGE{
    	int cnt,hd[W],nxt[N],to[N];
    	void add(int x,int y){nxt[++cnt]=hd[x],hd[x]=cnt,to[cnt]=y;}
    }buc[16];
    
    ull n,m,a1,a2;
    us val[N][16],mp[W],qq[16];
    int main(){
    	cin>>n>>m>>a1>>a2,gen(n,a1,a2);
    	for(int i=0;i<n;i++)
    		for(int j=0;j<16;j++){
    			for(int k=0;k<16;k++)
    				val[i][j]+=s[i][j*16+k]<<k;
    			buc[j].add(val[i][j],i);
    		}
    	for(int i=1;i<W;i++)mp[i]=mp[i>>1]+(i&1);
    	for(int i=0,las=0,k;i<m;i++,mem(qq,0)){
    		for(int j=0,vv=0;j<64;j++,vv=0){
    			char s=gc;
    			if(isdigit(s))vv=s-'0';
    			else if(s>='A'&&s<='F')vv=10+s-'A';
    			else {j--; continue;}
    			for(int l=0;l<4;l++)q[j*4+l]=(vv>>3-l)&1;
    		}
    		bool ok=0; k=read();
    		for(int j=0;j<16;j++)
    			for(int l=0;l<16;l++)
    				qq[j]+=(q[j*16+l]^las)<<l;
    		for(int j=0;j<16;j++){
    			for(int p=buc[j].hd[qq[j]];p;p=buc[j].nxt[p]){
    				int it=buc[j].to[p],cnt=0;
    				us *pval=val[it],*pq=qq;
    				for(int l=0;l<16;l++,pval++,pq++){
    					cnt+=mp[(*pval)^(*pq)];
    					if(cnt>k)break;
    				} if(cnt<=k){ok=1; break;}
    			} if(ok)break;
    		} cout<<(las=ok)<<'\n';
    	}
        return 0;
    }
    
    • 1

    信息

    ID
    7114
    时间
    2500ms
    内存
    384MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者