zoukankan      html  css  js  c++  java
  • 疑惑 题解

    一、题目:


    二、思路:

    这道题 Robert_JYH 说是一道简单题,在这里向他致以最崇高的膜拜。

    要做出来这道题,我们首先得明白亦或的本质,即“相同与不同”。相同就是0,不同就是1。

    现在来考虑这样一个性质:设 ({a_n}) 是一个从小到大排好序的序列。那么 (minlimits_{i,j}{a_ioplus a_j}=minlimits_{1leq i<n}{a_ioplus a_{i+1}}),即序列中两个元素亦或起来的最小值一定产生于相邻的两个元素之间。

    要说明这个性质成立,我们只需说明 (forall 0leq x<y<z),一定有 (xoplus zgeq xoplus y)(xoplus z geq yoplus z)。定义 (p(x,y)) 为从高位向低位看,(x)(y) 第一个不同的位。我们考虑这样一个过程,将 (x) 一点一点的向上增加,那么一定是 (x) 的低位先变动、(x) 的高位后变动。在这个过程中,(x) 先达到 (y),再达到 (z)。所以一定有 (p(x,z)geq p(x,y))。当然,这只是一个很不严谨的、非常感性的理解。具体证明看下面:

    最后,设 DP 状态为 (f[i]) 表示强制以 (i) 结尾的合法子序列的数目。则有 DP 转移方程

    [f[i]=1+sumlimits_{{j|a_ioplus a_jgeq x}}f[j] ]

    时间复杂度:(O(n^2))

    如何优化呢?看到亦或,当然要想到trie树。每次只需在trie树找出与 (a_i) 亦或起来大于等于 (x) 的所有数对应的DP值之和即可。

    时间复杂度:(O(nlog {maxa}))

    三、代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    #define FILEIN(s) freopen(s".in", "r", stdin);
    #define FILEOUT(s) freopen(s".out", "w", stdout)
    #define mem(s, v) memset(s, v, sizeof s)
    
    inline long long read(void) {
        long long x = 0, f = 1; char ch = getchar();
        while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
        while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
        return f * x;
    }
    
    const int maxn = 3e5 + 5, mod = 998244353;
    
    int n, sz = 1;
    long long X, a[maxn], f[maxn];
    
    int trans[maxn * 80][2];
    long long sum[maxn * 80];
    
    inline int call(long long x, int i) { return (x >> i) & 1; }
    
    inline void insert(long long x, long long val) {
        int p = 1;
        for (int i = 59; i >= 0; -- i) {
            int now = call(x, i);
            if (!trans[p][now]) trans[p][now] = ++ sz;
            p = trans[p][now];
            (sum[p] += val) %= mod;
        }
    }
    
    inline long long query(long long x) {
        int p = 1;
        long long res = 0;
        for (int i = 59; i >= 0; -- i) {
            int now1 = call(x, i), now2 = call(X, i);
            if (now2 == 0) {
                if (trans[p][now1 ^ 1]) res += sum[trans[p][now1 ^ 1]];
            } 
            if (!trans[p][now1 ^ now2]) trans[p][now1 ^ now2] = ++ sz;
            p = trans[p][now1 ^ now2];
        }
        (res += sum[p]) %= mod;
        return res;
    }
    
    int main() {
        FILEIN("xor"); FILEOUT("xor");
        n = read(); X = read();
        for (int i = 1; i <= n; ++ i)
            a[i] = read();
        sort(a + 1, a + n + 1); 
        f[1] = 1;
        insert(a[1], f[1]);
        for (int i = 2; i <= n; ++ i) {
            int tmp = query(a[i]);
            f[i] = 1 + tmp;
            insert(a[i], f[i]);
        }
        long long res = 0;
        for (int i = 1; i <= n; ++ i) (res += f[i]) %= mod;
        printf("%lld
    ", res);
        return 0;
    }
    
  • 相关阅读:
    数据仓库建设随笔(2)
    实战剖析三层架构2:实例代码
    数据仓库建设随笔(1)
    如何正确地死磕一个问题
    finally块中的代码一定会执行吗
    eclipse中任务进度的使用
    如何在单元测试编码实现类的访问器?这里给出一个答案
    SplitContainer.SplitterDistance属性值设置应注意的与FixedPanel有关
    再谈ReportingService报表中数据源类型为存储过程的数据集如何使用多值参数
    工作流加载及本地通信服务常见的异常
  • 原文地址:https://www.cnblogs.com/little-aztl/p/14829294.html
Copyright © 2011-2022 走看看