夏季每日一题打卡day1 —— AcWing 3485. 最大异或和

Posted Johnny*

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了夏季每日一题打卡day1 —— AcWing 3485. 最大异或和相关的知识,希望对你有一定的参考价值。

【题目描述】
在这里插入图片描述

AcWing 3485. 最大异或和

解法一

【思路】

异或的一些性质:
a ^ 0 = a
a ^ a = 0
类比前缀和知识:
对于原序列: 0 a1 a2 a3 a4 a5 a6
使用s数组存储上述序列的异或得到: 0 a1 a1^a2 a1^a2^a3 a1^a2^a3^a4 ……
则 计算a2^a3^a4 =  (a1^a2^a3^a4)  ^ (a1)
               = s[4] ^s[1]
异或多余那一段本身,可以消除多余那一段的影响

过 10/13 的数据

import java.util.Scanner;
public class Main{
    static int N = 100010;
    static int s[] = new int[N]; // 异或数组
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt(), m = reader.nextInt();
        
        for(int i = 1; i <= n; i ++){
            int x = reader.nextInt();
            s[i] = s[i - 1] ^ x;
        }
        
        int max = 0;
        //枚举区间长度
        for(int len = 0; len <= m; len ++){
            //子数组 [l: r]
            for(int l = 1; l + len - 1 <= n; l ++){
                int r = l + len - 1;
                int res = s[r] ^ s[l - 1];
                if( res > max) max = res;
            }
        }
        
        System.out.println(max);
        
    }
}

【思路】

在这里插入图片描述

解法二

二进制的每一位对应Trie的一条边
Trie 区间和
使用Trie存储异或结果二进制表示的01串
要想使得异或结果尽可能地大,根据按位异或的特点(相同为0,相异位1),每一位尽可能的选择与要异或的数对应位相反的数。那么对于每一个s[i], 从高位到低位应该尽可能地选择与s[i]相异的01串 s [ j ] (i - j < m)。
每次筛掉与该位相同的集合,Trie从上往下走的过程就对应不断筛掉一半区间的过程。时间复杂度:32log(32*N)

import java.util.Scanner;
public class Main{
    static int N = 100010, M = 100010 *31;
    
    //son 第一维表示节点编号  第二维表示0(右)、1(左)子节点
    //存储的p节点的0或1儿子的节点编号
    static int son[][] = new int[M][2]; //有N个数 每个数是一个31位的01串  一共有M个节点 
    static int cnt[] = new int[M]; //以编号为i为根节点的01串(数)的个数
    static int idx;
    static int s[] = new int[N]; // 异或数组
    
    public static void insert(int x, int v){
        int p = 0;
        //从高位往低位枚举
        for(int i = 30; i >=0; i --){
            int u = x >> i & 1;
            
            if( son[p][u] == 0 ) son[p][u] = ++idx; //p不存在u这个子节点则new一个
            //p走到儿子节点上
            p = son[p][u];
            cnt[p] += v;
        }
        
    }
    
    public static int query(int x){
        int p = 0, res = 0;
        for(int i = 30; i >= 0; i --){
            int u = x >> i & 1;
            //相异的数存在
            if( cnt[ son[p][1 - u] ] != 0 ){
                p = son[p][1 - u];
                res = res * 2 + 1; //这一位是1
            }else{
                p = son[p][u]; //走到子节点
                res = res * 2 + 0; //这一位是0
            }
        }
        return res;
    }
    
    
    
    public static void main(String args[]){
        Scanner reader = new Scanner(System.in);
        int n = reader.nextInt(), m = reader.nextInt();
        
        for(int i = 1; i <= n; i ++){
            int x = reader.nextInt();
            s[i] = s[i - 1] ^ x;
        }
        int res = 0;
        insert(s[0], 1);
        
        for(int i = 1; i <= n; i ++){
            //要求异或和连续数组是:s[max(i-m,0)]~s[i] 
            //也就是S[j]范围是s[ i - m - 1 ,i- 1]
            //滑出窗口的数要移除: 
            if( i > m )  insert(s[i - m - 1], - 1);
            res = Math.max(res, query(s[i]));
            insert(s[i], 1);
        }
        System.out.println(res);
      
        
    }
}

143. 最大异或对

【题目描述】

143. 最大异或对

【思路】
如果要求最大的异或对是哪两个,可以用如下

import java.io.*;
import java.lang.Math;
class Main{
    static int N = 100010, M = 100010 *31;
    
    static int idx;
    static int son[][] = new int[M][2];
    static int a[] = new int[N];
    
    public static void insert(int x){
        int p = 0;
        for(int i = 30; i >= 0; i --){
            int u = x >> i & 1;
            if( son[p][u] == 0 ) son[p][u] = ++ idx;
            p = son[p][u];
        }
        
    }
    
    public static int query(int x){
        
        int res = 0, p = 0;
        for(int i = 30; i >= 0; i --){
            int u = x >> i & 1;
            if( son[p][1 - u] == 0){//相异的数不存在
                res = res * 2 + u ;
                p = son[p][u];
            }
            else {
                res = res * 2 + 1 - u;//相异的数存在
                p = son[p][1 - u];
            }
            
        }
        return res;
    }
    
    public static void main(String args[]) throws Exception{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(bf.readLine());
        String s[] = bf.readLine().split(" ");
        for(int i = 0; i < n; i++) a[i] = Integer.parseInt(s[i]);
        int res = 0; // 最小为0(相同的数异或为0)
        
        for(int i = 0; i < n; i++){
            insert(a[i]);//先往tire中插入数据 避免空集特判
        }
        for(int i = 0; i < n; i++){
            int t = query(a[i]);
            res = Math.max(res, a[i] ^ t);
        }
        System.out.println(res);
    }
}

1414. 牛异或

以上是关于夏季每日一题打卡day1 —— AcWing 3485. 最大异或和的主要内容,如果未能解决你的问题,请参考以下文章

夏季每日一题打卡day4 —— AcWing 3502. 不同路径数

夏季每日一题打卡day5——AcWing 3489. 星期几

夏季每日一题打卡day3 —— AcWing 3499. 序列最大收益

解题报告Acwing每日一题 夏季 [1/16]

AcWing夏季每日一题--最长公共子序列

春季每日一题打卡day2 —— AcWing 435. 传球游戏