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 }
  • 相关阅读:
    利用jquery获取html中被选中的input的值
    获取表单选中的值(利用php和js两种方式)
    复习
    Ajax请求中的async:false/true的作用
    Jquery
    C#创建控制台项目引用Topshelf的方式,部署windows服务。
    你循环的时候就可以给他们赋值了,那么就不用addClass,再根据类选择器处理,代码能一气呵成就别写成两段了
    SQL server 数据库中插入中文变???格式乱码的问题另一种容易忽略的情况(C#操作dapper)
    SQL 两个表有关联,通过其中一个表的列,更新另一个表的列。
    SQL server 存储过程中 列传行
  • 原文地址:https://www.cnblogs.com/Annetree/p/7290234.html
Copyright © 2011-2022 走看看