zoukankan      html  css  js  c++  java
  • HDU 6059 17多校3 Kanade's trio(字典树)

    Problem Description
    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]))

    There are T test cases.

    1T20

    1n5105

    0A[i]<230
     
    Input
    There is only one integer T on first line.

    For each test case , the first line consists of one integer n ,and the second line consists of n integers which means the array A[1..n]
     
    Output
    For each test case , output an integer , which means the answer.
     
    Sample Input
    1
    5
    1 2 3 4 5
     
    Sample Output
    6
     
    启发博客:http://blog.csdn.net/dormousenone/article/details/76570172
    摘:

    利用字典树维护前 k-1 个数。当前处理第 k 个数。

    显然对于 k 与 i 的最高不相同位 kp 与 ip :

    当 ip=0 , kp=1 时,该最高不相同位之前的 ihigher=khigher 。则 jhigher 可以为任意数,均不对 i, k 更高位(指最高不相同位之前的高位,后同)的比较产生影响。而此时 jp 位必须为 0 才可保证不等式 (AiAj)<(AjAk) 成立。

    当 ip=1,kp=0 时,jp 位必须为 1 ,更高位任意。

    故利用数组 cnt[31][2] 统计每一位为 0 ,为 1 的有多少个(在前 K-1 个数中)。在字典树插入第 k 个数时,同时统计最高不相同位,即对于每次插入的 p 位为 num[p] (取值 0 或 1),在同父节点对应的 1-num[p] 为根子树的所有节点均可作为 i 来寻找 j 以获取对答案的贡献。其中又仅要求 jp 与 ip (ip 值即 1-num[p]) 相同,故 jp 有 cnt[p][ 1-num[p] ] 种取值方案。

    但是,同时需要注意 i 与 j 有在 A 数组的先后关系 (i<j) 需要保证。故在字典树中额外维护一个 Ext 点,记录将每次新加入的点与多少原有点可构成 i, j 关系。在后续计算贡献时去掉。

    其余详见代码注释。

     1 #include <iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<queue>
     5 #include<map>
     6 #include<vector>
     7 #include<cmath>
     8 #include<cstring>
     9 using namespace std;
    10 long long ans1,ans2;
    11 int num[35];//每一个数字的二进制转化
    12 int cnt[35][2];//cnt[i][j]记录全部插入数字第i位为0、1分别的数字
    13 
    14 struct trie
    15 {
    16     trie* next[2];
    17     int cnt,ext;
    18     trie()
    19     {
    20         next[0]=NULL;
    21         next[1]=NULL;
    22         cnt=0;//拥有当前前缀的数字个数
    23         ext=0;//
    24     }
    25 };
    26 
    27 void calc(trie* tmp,long long c)
    28 {
    29     ans1+=tmp->cnt*(tmp->cnt-1)/2;
    30     ans2+=(c-tmp->cnt)*tmp->cnt-tmp->ext;
    31 }
    32 
    33 void insert(trie* r)
    34 {
    35     int i;
    36     for(i=1;i<=30;i++)
    37     {
    38         if(r->next[num[i]]==NULL)
    39             r->next[num[i]]= new trie;
    40         if(r->next[1-num[i]]!=NULL)
    41             calc(r->next[1-num[i]],cnt[i][1-num[i]]);
    42         r=r->next[num[i]];
    43         r->cnt++;
    44         r->ext+=cnt[i][num[i]]-r->cnt;
    45         //每个点存下同位同数不同父亲节点的数字个数且序号比本身小的
    46     }
    47     return ;
    48 }
    49 
    50 int main()
    51 {
    52     int T,n,tmp;
    53     scanf("%d",&T);
    54     while(T--)
    55     {
    56         scanf("%d",&n);
    57         trie root;
    58         ans1=0;//i,j选自同父亲节点
    59         ans2=0;//i选自同父亲节点,j选择同位不同数不同父亲节点
    60         memset(cnt,0,sizeof(cnt));
    61         while(n--)
    62         {
    63             scanf("%d",&tmp);
    64             for(int i=30;i>=1;i--)//这样可以保证不同大小的数字前缀都为0
    65             {
    66                 num[i]=tmp%2;
    67                 cnt[i][num[i]]++;
    68                 tmp/=2;
    69             }
    70             insert(&root);
    71         }
    72         printf("%lld
    ",ans1+ans2);
    73     }
    74     return 0;
    75 }
  • 相关阅读:
    Linux内核RPC请求过程
    二分图
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 合并石子
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 摩尔斯电码
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 文本加密
    Java蓝桥杯 算法提高 九宫格
    Java蓝桥杯 算法提高 九宫格
  • 原文地址:https://www.cnblogs.com/Annetree/p/7290234.html
Copyright © 2011-2022 走看看