zoukankan      html  css  js  c++  java
  • CF1163E Magical Permutation

    题目来源:Codeforces Round #558 (Div. 2) CF1163E Magical Permutation

    算法:线性基

    题目大意

    题目链接

    给定一个,含有(n)个互不相同正整数的集合(S)

    我们称一个排列是合法的,当且仅当同时满足如下两个条件:

    1. 这是一个(0,1,dots ,2^x-1)的排列,其中(x)是一个非负整数。
    2. 排列里,任意相邻两数的异或值,都出现在(S)中。

    请求出,最长的合法排列。换句话说,请你找到一个最大的(x),并构造出一个长度为(2^x)的合法排列。

    数据范围:(1leq nleq 2 imes 10^5)(S)集合里的数(leq2 imes 10^5)

    本题题解

    (S)里最大的数为(M)

    如果排列的二进制下最高位,超过了(S)里最大的数(即(2^{x-1}>M)),那么这样的排列一定是不合法的。因为最高位一定会出现在异或值中,但它无法被(S)里的数表示出来。因此,满足条件的(x)不超过(log_2M+1)。于是我们考虑枚举所有(x),判断它是否可行。

    引理:一个(x)可行当且仅当,(0,1,dots,2^x-1)都能被表示为(S)的一个子集的异或和。

    证明-必要性

    考虑一个合法的排列,(p_0,p_1,dots ,p_{2^x-1}),设(p_t=0)

    首先,(p_t)就是一个空集的异或和,所以对(p_t)显然满足条件。

    因为排列合法,所以在(p_{t+1},p_{t+2},dots ,p_{2^x-1})中,每个数和它前面一个数的异或值,都属于(S)。具体来说,设(c_i=p_{i-1}operatorname{xor}p_{i}),则(forall i>t:c_iin S),因此(p_{t+1},p_{t+2},dots ,p_{2^x-1})都能被表示为一段连续的(c_i)的异或和,也就是(S)里若干个数的异或和。

    类似地,在(p_{t-1},p_{t-2},dots,p_0)中,每个数和它后面一个数的异或值,都属于(S)。设(d_i=p_{i}operatorname{xor}p_{i+1}),则(forall i<t:d_iin S),因此(p_{t-1},p_{t-2},dots,p_0)都能被表示为一段连续的(d_i)的异或和,也就是(S)里若干个数的异或和。

    由此就证明了:【(0,1,dots,2^x-1)都能被表示为(S)的一个子集的异或和】是一个长度为(2^x)的排列合法的必要条件。枚举(x)后,我们可以通过对(S)建线性基,看线性基前(x)位是否填满,来检查(x)是否满足这个必要条件。

    接下来要证明充分性,相当于把这个排列构造出来。也正是题目要我们做的事情。

    现在我们知道,(0,1,dots,2^x-1)都能被表示为(S)的一个子集的异或和。根据线性基的理论,对(S)建线性基后,(S)的每个子集,都对应线性基的一个子集,它们异或和相等。所以(0,1,dots,2^x-1)每个数,都能被表示为:【(S)里,用来建线性基的,这(x)个数】的一个子集。并且每个数对应的子集互不相同:用来建线性基的有(x)个数,正好形成(2^x)个子集,和每个值一一对应。

    通过线性基,我们能求出,每个值对应了哪个子集。前面说了,这些子集互不相同。于是把它们用二进制表示为(0,1,dots,2^x-1)

    那么问题转化为,把(0,1,dots,2^x-1)(所有子集)重新排列,使得任意相邻两个数,只有一位二进制为不同。这就是格雷码的定义,可以采用「CSP-S 2019」格雷码这题题面里介绍的构造方法。

    时间复杂度(O(nlog n+nlog M+M))

    参考代码:

    //problem:
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    
    template<typename T>inline void ckmax(T& x,T y){x=(y>x?y:x);}
    template<typename T>inline void ckmin(T& x,T y){x=(y<x?y:x);}
    
    const int MAXN=2e5,LOG=18;
    int n;
    uint s[MAXN+5];
    uint mask_to_val[MAXN+5];
    struct LinerBase{
    	int size;
    	uint base[MAXN+5],mask[MAXN+5],val[MAXN+5];
    	void insert(const uint& v){
    		uint t=v;
    		uint ma=0;
    		for(int i=LOG;i>=0;--i) if((t>>i)&1) {
    			if(!base[i]){
    				base[i]=t;
    				++size;
    				ma|=(1<<(size-1));
    				mask[i]=ma;
    				val[size]=v;
    				return;
    			}
    			else{
    				t^=base[i];
    				ma^=mask[i];
    			}
    		}
    	}
    	uint query_mask(const uint& v){
    		uint t=v;
    		uint ma=0;
    		for(int i=LOG;i>=0;--i) if((t>>i)&1) {
    			assert(base[i]);
    			t^=base[i];
    			ma^=mask[i];
    		}
    		return ma;
    	}
    }B;
    vector<uint> get_gray(uint x){
    	if(x==0){
    		vector<uint> res(1,0);
    		return res;
    	}
    	vector<uint> res=get_gray(x-1);
    	uint len=(1u<<(x-1));
    	for(uint i=0;i<len;++i){
    		res.push_back(res[len-1-i] | (1u<<(x-1)));
    	}
    	return res;
    }
    int main() {
    	cin>>n;
    	for(int i=1;i<=n;++i){
    		cin>>s[i];
    	}
    	sort(s+1,s+n+1);
    	int j=0;
    	int x=-1;
    	for(int i=0;i<=LOG;++i){
    		while(j+1<=n && s[j+1]<(1u << i)){
    			++j;
    			B.insert(s[j]);
    		}
    		if(B.size==i) x=i;
    	}
    	assert(x!=-1);
    	for(uint i=0;i<(1u<<x);++i){
    		mask_to_val[B.query_mask(i)]=i;
    	}
    //	cerr<<x<<endl;
    //	for(uint i=0;i<(1u<<x);++i)
    //		cerr<<mask_to_val[i]<<" ";
    //	cerr<<endl;
    	vector<uint> v=get_gray(x);
    	cout<<x<<endl;
    	for(uint i=0;i<(1u<<x);++i){
    		cout<<mask_to_val[v[i]]<<" ";
    	}
    	cout<<endl;
    	return 0;
    }
    
  • 相关阅读:
    008. redis 主从复制原理、断点续传、无磁盘化复制、过期 key 处理
    007.redis replication 以及 master 持久化对主从架构的安全意义
    006. redis 如何通过读写分离来承载读请求 QPS 超过 10 万 +?
    005.在项目中部署 redis 企业级数据备份方案以及各种踩坑的数据恢复容灾演练
    人月神话---向进度落后的项目中增加人手,只会使进度更加落后
    人月神话---空泛的估算
    人月神话---不为系统测试安排足够的时间简直就是一场灾难
    人月神话---成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此
    springmvc其他类获取request记得web.xml
    gson转换问题
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/13640005.html
Copyright © 2011-2022 走看看