9.22 xor三元组计数

Posted venividivici

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.22 xor三元组计数相关的知识,希望对你有一定的参考价值。

题意

给定一个长为\(N\)的序列\(a\),请求出所有满足下列条件的三元组\(<x,y,z>\)

  • \(1\leq x < y < z \leq N\)
  • \(a_x \oplus a_y < a_y \oplus a_z\)

这里的\(\oplus\)运算指按位异或


解法

异或\(+\)序列问题\(\to\) 01Trie

很自然的想到枚举\(y\),对\(1\to y-1\)\(y+1\to N\)分别维护一颗Trie,计算符合条件的\(<x,z>\)二元组个数

我们可以发现,如果按位考虑的话,比较\(x,\)\(z\)\(y\)的异或值大小,实际上起到决定作用的是\(x,z\)的二进制位从高到低第一个不同的位

暴力Trie上DFS的复杂度显然是不对的,可能达到指数级别

由于动态维护Trie每次只增删一条链,考虑统计这条链所带来的影响

\(f[i][0/1]\)为从高位到低位考虑,前\(i-1\)位相同,第\(i\)位不同的\(<x,z>\)对数。其中,第二维为\(0\)代表\(x\)的第\(i\)位为\(0\)\(z\)的第\(i\)位为\(1\)(所以我们的Trie是由高位到低位建立的)

这样我们只需在Trie上动态维护\(f\)数组,统计答案时直接用\(f\)数组更新即可


代码

#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

const int MAX_N = 1e5 + 10;
const int lg = 30;

int read();

int a[MAX_N];

long long ans;
long long f[lg + 1][2];

struct Trie 
    
    int root, cnt;
    
    struct node 
        int sum;
        int ch[2];  
     t[MAX_N * lg];
    
    void clear() 
        for (int i = 1; i <= cnt; ++i)  
            t[i].ch[0] = t[i].ch[1] = t[i].sum = 0;
        cnt = root = 1;
    
    
    void ins(int x) 
        int p = root;
        for (int i = lg; i >= 0; --i) 
            int c = x >> i & 1;
            if (!t[p].ch[c])
                t[p].ch[c] = ++cnt;
            p = t[p].ch[c]; 
            t[p].sum++;
        
    
    
    void era(int x) 
        int p = root;
        for (int i = lg; i >= 0; --i) 
            int c = x >> i & 1;
            p = t[p].ch[c];
            t[p].sum--;
        
    
        
 tr_a, tr_b;

// f[x][0] : pre 0 suf 1
// f[x][1] : pre 1 suf 0
void add(int x) 
    int p = 1;
    for (int i = lg; i >= 0; --i) 
        int c = x >> i & 1;
        f[i][c] += tr_b.t[tr_b.t[p].ch[c ^ 1]].sum;
        p = tr_b.t[p].ch[c];
    


void del(int x) 
    int p = 1;
    for (int i = lg; i >= 0; --i) 
        int c = x >> i & 1;
        f[i][c ^ 1] -= tr_a.t[tr_a.t[p].ch[c ^ 1]].sum;
        p = tr_a.t[p].ch[c];
    


int main() 
    
//  freopen("xyz.in", "r", stdin);
//  freopen("xyz.out", "w", stdout);
    
    int T = read();
    
    while (T--) 
        
        int N = read();
        for (int i = 1; i <= N; ++i)  a[i] = read();
        
        ans = 0; 
        tr_a.clear(), tr_b.clear();
        memset(f, 0, sizeof f);
        
        for (int i = 2; i <= N; ++i)  tr_b.ins(a[i]);
        
        for (int i = 2; i < N; ++i) 
            del(a[i]), tr_b.era(a[i]);
            add(a[i - 1]), tr_a.ins(a[i - 1]);
            for (int j = lg; j >= 0; --j) 
                ans += f[j][a[i] >> j & 1];
        
        
        printf("%lld\n", ans);
    
    
    return 0;


int read() 
    int x = 0, c = getchar();
    while (!isdigit(c))  c = getchar();
    while (isdigit(c))   x = x * 10 + c - 48, c = getchar();
    return x;

以上是关于9.22 xor三元组计数的主要内容,如果未能解决你的问题,请参考以下文章

1442. 形成两个异或相等数组的三元组数目

元组中的 OCaml 意外类型不匹配

减少单词列表,将元组计数到聚合键

Codeforces 724 G Xor-matic Number of the Graph 线性基+DFS

CF724G. Xor-matic Number of the Graph

hdu 5654 xiaoxin and his watermelon candy 树状数组维护区间唯一元组