• 2021“MINIEYE杯”中国大学生算法设计超级联赛(1)1006.Xor sum


    Xor sum

    题目链接

    http://acm.hdu.edu.cn/showproblem.php?pid=6955

    题意

    给定 (n) 个数,求异或和大于等于 (k) 的最短的区间左右端点,如果有多个答案,输出左端点编号最小的那个。

    思路

    由于异或的自反性,我们做个前缀异或和可将区间异或和转换成俩个数的异或和。

    对于每一个 (a_i) ,要找到以 (a_i) 作为结尾的子串,只要和 (i) 之前的所有的异或前缀和做一次异或运算,就能得到以 (i) 为结尾的异或前缀和。

    我们把前 (i - 1) 项结尾的异或前缀和用字典树进行拆位储存, 从高位往低位枚举, 类似数位dp, 将大于的答案纳入考虑范围,不断缩小左端点, 得到以 (a_i) 结尾的最短的目标区间。

    AC_Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn = 3e7 + 50;
    ll a[maxn];
    int tot = 0;
    int tree[maxn][2];
    int cnt[maxn];
    void insert(int x, int pos){
        int rt = 0;
        for(int i = 31;i >= 0;i--){
            int now = x >> i & 1;
            if(!tree[rt][now]){
                tree[rt][now] = ++tot;
            }
            rt = tree[rt][now];
            cnt[rt] = max(cnt[rt], pos);
        }
    }
    void find(int x, int k, int &L){
        int rt = 0;
        for(int i = 31;i >= 0;i--){
            int nowx = x >> i & 1;
            int nowk = k >> i & 1;
            if(!nowx){
                if(!nowk){
                    L = max(L, cnt[tree[rt][1]]);
                    if(!tree[rt][0]) return;
                    rt = tree[rt][0];
                }
                else{
                    if(!tree[rt][1]) return;
                    rt = tree[rt][1];
                }
            }
            else{
                if(!nowk){
                    L = max(L, cnt[tree[rt][0]]);
                    if(!tree[rt][1]) return;
                    rt = tree[rt][1];
                }
                else{
                    if(!tree[rt][0]) return;
                    rt = tree[rt][0];
                }
    
            }
        }
        L = max(L, cnt[rt]);
    }
    int main()
    {
        std::ios::sync_with_stdio(false);
        int t;
        cin >> t;
        while(t--){
            int n, k;
            cin >> n >> k;
            for(int i = 1;i <= n;i++){
                cin >> a[i];
                a[i] ^= a[i - 1];
            }
            ll len = n + 1;
            ll ansL = 0;
            for(int i = 1;i <= n;i++){
                if(a[i] >= k){
                    ansL = i;
                    len = i;
                    break;
                }
            }
            insert(0, 0);
            for(int i = 1; i <= n;i++){
                int L = 0;
                find(a[i], k, L);
                if(i - L < len && L){
                    len = i - L;
                    ansL = L + 1;
                }
                insert(a[i], i);
            }
            if(len != n + 1) cout << ansL << " " << ansL + len - 1 << endl;
            else cout << -1 << endl;
            for(int i = 0;i <= tot;i++) tree[i][0] = tree[i][1] = 0, cnt[i] = 0;
            tot = 0;
        }
        return 0;
    }
    
    
  • 相关阅读:
    jQuery源码解析(架构与依赖模块)第二章 核心模块
    jQuery源码解析(架构与依赖模块)第一章 理解架构
    js中运算符的优先级
    JS将时间与时间戳互转
    关于JavaScript scope的一切
    java中继承以及其他相关内容
    java中数组的内容
    关于java中的引用数据类型
    关于java的源文件结构以及常用的包
    Java语言的基础内容
  • 原文地址:https://www.cnblogs.com/Carered/p/15037526.html
Copyright © 2020-2023  润新知