zoukankan      html  css  js  c++  java
  • # NOI.AC省选赛 第五场T1 子集,与&最大值

    NOI.AC省选赛 第五场T1

    A. Mas的童年

    题目链接

    http://noi.ac/problem/309

    思路

    0x00

    (n^2)的暴力挺简单的。

    ans=max(ans,xor[j-1]+xor[j-1]^xor[i]);
    

    01trie树求最大异或和相信大家都会。不会看这里.
    这与我们今天这个题目有关吗?
    毫无关系。
    xor[i]的某一位为1,xor[j]的那一位不管是啥,贡献都是为1。
    而xor[i]的某一位为0,xor[j]的贡献是2或0。(xor[j]位上为1贡献为2)
    (这里的1,2都是2^(k)的1倍,两倍)
    所以我们只要考虑xor[i]的位上为0的贡献。
    将xor[i]取反,就是求与(&)最大值。
    最后整理一下就可以计算出答案了。

    0x01

    如何求与(&)最大值
    把每个插入的值的所有子集装进一个桶里。
    然后从大到小选择判断是否在桶里面出现过,因为从大到小枚举,所以一定不会冲突掉,就好了,这看代码比较清晰。
    相似的,我们也可以求或(|)的最大值

    0x02

    复杂度?
    x如果枚举过了就不用再枚举
    那复杂度就是每个数枚举下二进制
    ((nlogn))
    当然如果插入数的上限太大了话应该就做不了。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e6+7;
    int read() {
    	int x=0,f=1;char s=getchar();
    	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    	return x*f;
    }
    int n,a[N],xo[N],tong[N];
    void mark(int x) {//枚举子集
    	tong[x]=1;
    	for(int i=0;i<20;i++)
    		if((x>>i&1)&&(!tong[x^(1<<i)]))
    			mark(x^(1<<i));
    }
    int askand(int x) {//RT
    	int ans=0;
    	for(int i=19;i>=0;--i)
    		if(!((1<<i)&x) && tong[ans|(1<<i)]) ans|=(1<<i);
    	return ans;
    }
    int main() {
    	n=read();
    	for(int i=1;i<=n;++i) a[i]=read(),xo[i]=xo[i-1]^a[i];
    	for(int i=1;i<=n;++i) {
    		cout<<askand(xo[i])*2+xo[i]<<" ";
    		mark(xo[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    1837. Isenbaev's Number(floyd)
    1414. Astronomical Database(STL)
    1067. Disk Tree(字符串)
    1682. Crazy Professor(并查集)
    1650. Billionaires(线段树)
    1316. Electronic Auction(树状数组)
    1701. Ostap and Partners(并查集-关系)
    大数字运算——2、BigDecimal
    大数字运算——1、BigInteger
    java中的访问修饰符2
  • 原文地址:https://www.cnblogs.com/dsrdsr/p/10628676.html
Copyright © 2011-2022 走看看