zoukankan      html  css  js  c++  java
  • sgu275 To xor or not to xor

    To xor or not to xor

    给你 n 个非负整数序列 A1, A2, ..., AN。你需要寻找这个序列的一个子序列:Ai1, Ai2, ..., Aik (1<=i1 <i2 <...<ik <=N)满足Ai1 XORAi2 XOR...XORAik最大。

    Xor 即为不进位的二进制加法。满足: 0+0=0

    1+0=1 1+1=0

    在 PASCAL 中,你可以使用 a:=b xor c 语句。其中 a,b,c 均为整型。 输入格式:(xor.in)

    第一行包含一个正整数 n,第二行包含整数序列 A1, A2, ..., AN。 输出格式:(xor.out)

    包含一个整数,表示 Ai1 XOR Ai2 XOR ... XOR Aik 的最大可能值。

    样例输入:

    3
    11 9 5

    样例输出:

    14

    数据规模:
    对于 30%的数据,n<=10
    对于 60%的数据,n<=20,ai<=1023
    对于 100%的数据,0 <= Ai <= 10^18,0<n<=100。

    思路:我们要求的是子序列异或起来的最大值,而0 <= Ai <= 10^18刚好可以用long long存下,

    所以可以把每一个Ai看作二进制数,尽量使ans的高位是1,这样就可以保证求出来的是最大值.

    开始在判断最高位(1<<63)时非常简单,

    只要O(n)扫一遍,每次判断Ai在这一位(1<<63)是不是1就可以,只要有一个Ai这一位是1就可以满足.

    但是马上就会发现选不同的数异或都可以使这一位(1<<63)是1,但是之后不一定最优.

    这个时候就要给ans一个反悔的机会.

    怎么样反悔呢?

    怎么样能在异或了Ai之后枚举下一个二进制位时消除Ai的影响又不影响高位呢(相当于异或了别的数)?

    (这里很不好想,我卡这儿半天,各位可以思考一下再看)

    (结合一下异或的性质)

    我们知道A^B^B仍然等于A,而且异或满足结合律

    所以在Ans^Ai之后反悔的话,只要把其他这一二进制位是1的Aj都^Ai就可以啦!

    这样Ans^Ai^Aj^Ai-->Ans^Aj,这就相当于异或了别的数啦~

    选多个Ai也是一样的,在异或Ak之后再选的话,肯定要选偶数个才能保证最优,

    偶数个异或起来也是可以消掉的并不影响答案.

    一些细节:枚举的到Aj时要判断一下当前ans这一位是不是1,如果是的话才将ans^Aj

    但是不管ans这一位是什么,只要Aj这一位是1,就要将其他Ak^Aj,这样才能有足够的反悔机会,不会挤掉答案

    感觉有点像dp的二进制优化......?

    还有Ak^Aj的时候不能一个for异或下去,要不然j==k的时候Aj就成0了,之后的Ak不会改变,就会WA

    最后Aj赋成0就行

    (这么傻的错误应该只有我会犯了吧qwq)

    来跑个小样例~

    (对齐有点问题所以直接截图了)

    下面是代码

    #include<cstdio>
    #define ll long long
    using namespace std;
    int n;
    ll num[101];
    int main(){
        // freopen("xor.in","r",stdin);
        // freopen("xor.out","w",stdout);
        ll ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%lld",&num[i]);
        for(int i=63;i>=0;i--)//从高位开始枚举
            for(int j=1;j<=n;j++)
                if(num[j]&(1LL<<i)){//a[j]这一位是1
                    if((ans&(1LL<<i))==0)//ans这一位是0
                        ans^=num[j];
                    for(int k=1;k<=n;k++)//为保证之后最优
                        if((num[k]&(1LL<<i))&&k!=j)
                            num[k]^=num[j];
                    num[j]=0;
                }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    sap快捷登录
    转载(略有修改):Windows 8的承载网络设置方法(w8 创建无线网络/ap)
    转载:Keytool 工具介绍
    minecraft初探
    linux图像界面连接-xdm
    经典的始终经典(牛蛙)
    vmware install win8 and server2012 problem
    windows硬盘优化篇
    网络15软工个人作业5——软件工程总结
    个人作业4——alpha阶段个人总结
  • 原文地址:https://www.cnblogs.com/al76/p/9350387.html
Copyright © 2011-2022 走看看