[HDU]6059 Kanade's trio

来源:互联网 发布:js eval 编辑:程序博客网 时间:2024/06/16 05:52

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

题意

Give you an array A[1..n],you need to calculate how many tuples (i,j,k) satisfy that (i< j< k) and ((A[i] xor A[j])<(A[j] xor A[k]))

题解

看了别人题解大半天,才终于明白,随便记下自己的理解

对于所有的 ((A[i] xor A[j])<(A[j] xor A[k]))
假设我们用字典树记录了A[1 ~ k-1],当前加入 Ak
字典树中以第30位为根,假设当前处理到了第 p 位
Ak[p] 代表Ak 第 p 位的值,且AiAk 高位都是相同的
Ak[p]=1 时:
必然 Ai[p]=0Aj[p]=0 时才有价值,下面考虑Aj 的取值情况
1. Aj 的高位与AkAk 都相同的情况 1LL * dat[Fson].num * (dat[Fson].num - 1) / 2;
2. Aj 的高位与AkAk 不都都相同的情况 dat[Fson].num * (cnt[o][1-t] - dat[Fson].num) - dat[Fson].exn;

Ak[p]=0 时:同上讨论即可

注: 减去 dat[Fson].exn,dat[Fson].exn是 i > j 时 满足条件2 的情况

#include<stdio.h>#include<string.h>typedef long long LL;const int MAXN = 2e5 + 5;struct node {int num, exn, son[2]; } dat[31 * MAXN];LL ans = 0;int sz, cnt[31][2];inline void cle(int x) {    dat[x].son[0] = dat[x].son[1] = dat[x].num = dat[x].exn = 0;}inline void add(int n, int o) {    int z = 0;    while(o >= 0) {        int t = n>>o&1;        int &Fson = dat[z].son[1-t];        int &Tson = dat[z].son[  t];        if(Fson) {            ans += 1LL * dat[Fson].num * (dat[Fson].num - 1) / 2;            ans += 1LL * dat[Fson].num * (cnt[o][1-t] - dat[Fson].num) - dat[Fson].exn;        }        if(Tson) {            z = Tson;        }        else {            z = Tson = ++sz;            cle(Tson);        }        ++dat[z].num;        ++cnt[o][t];        dat[z].exn += cnt[o][t] - dat[z].num; // all of j < i in this node        --o;    }}int main(){    int T, n, x;    scanf("%d", &T);    while(T--) {        memset(cnt, 0, sizeof(cnt));        scanf("%d", &n);        ans = sz = 0;        cle(0);        while(n--) {            scanf("%d", &x);            add(x, 30);        }        printf("%lld\n", ans);    }    return 0;}
原创粉丝点击