• HDU 6059 Kanade's trio


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

    题意:给你一个数列,找出i<j<k且a[i]^a[j]<a[j]^a[k]的三元组个数;

    思路:字典树;

    可以知道,如满足以上关系,就是要找出a[i]和a[k]第一位不同的位,另a[j]的这一位与a[I]相同即可,那么就分为两种情况:

    (1)a[i],a[j],a[k]的前t-1位都相同,那么对答案的贡献就是d[Fson].num*(d[Fson].num-1)/2;

      这里Fson是当前位的兄弟节点,a[i],a[j]都在这个子树中,显然,必然有一大一小两个a[i],a[j]来满足;

    (2)a[i],a[k]的前t-1位都相同,a[j]不同,这里a[j]的前t-1为其实是什么不重要,所以加上第一种情况刚好是全部解,对答案的贡献为:

      d[Fson].num*(cnt[k][1-t]-d[Fson].num)-d[Fson].ng

      后面减去的是不合法的,实际上就是i,j的选取问题,d[Fson].num是我想要的i,cnt[k][1-t]-d[Fson].num是我要的j,但是问题是i,j是有先后顺序的

      我不能保证我要的j一定都在i的后面出现,但是,我们可以知道当插入一个节点时,如果要把这个节点作为i,前面出现过的节点肯定不能作为j,那么

      对于每一个新的i节点,有多少不合法的呢,是cnt[k][t]-d[z].num;这也很好理解,因为我们知道(2)中i和j不会再同一子树中,那么cnt[k][t]-d[z].num就是

      当前位相同的总数减去当前子树的数量,得到的就是,非同一子树中同位相同的比当前节点早插入的节点,即上面说的非法节点;

    代码:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int MAXN=2e5+5;
    struct Node
    {
        int num,ng,son[2];
    }d[31*MAXN];
    LL ans=0;
    int sz,cnt[31][2];
    
    inline void cle(int x)
    {
        d[x].son[0]=d[x].son[1]=d[x].num=d[x].ng=0;
    }
    
    void add(int n,int k)
    {
        int z=0; //插入时当前节点
        while(k>=0)
        {
            int t=n>>k&1;//插入数当前位
            int &Fson = d[z].son[1-t]; //这里用引用是因为要更新原始数据
            int &Tson = d[z].son[t];
            if(Fson)//如果我的兄弟节点存在,操作
            {
                ans+=1LL*d[Fson].num*(d[Fson].num-1)/2;//i,j,k前t-1位都相同
                ans+=1LL*d[Fson].num*(cnt[k][1-t]-d[Fson].num)-d[Fson].ng;//i,k前t-1位相同,j不一定相同,之所以减掉不成立的,是因为i,j是要有一个顺序
            }
            if(Tson)//如果下一位的节点存在,直接顺延下去
            {
                z=Tson;
            }
            else//如果下一位的节点,不存在,创建个新节点,并初始化
            {
                z=Tson=++sz;
                cle(z);
            }
            d[z].num++;
            cnt[k][t]++;
            d[z].ng+=cnt[k][t]-d[z].num;
            k--;
        }
    }
    
    int main()
    {
        //freopen("input.txt","r",stdin);
        int T,n,x;
        for(scanf("%d",&T);T;T--)
        {
            memset(cnt,0,sizeof cnt);
            scanf("%d",&n);
            ans=0,sz=0;
            cle(0);
            while(n--)
            {
                scanf("%d",&x);
                add(x,30);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    monkeyrunner之夜神模拟器的安装与使用(二)
    monkeyrunner之安卓开发环境搭建(一)
    MySQL 返回未包含在group by中的列
    MySQL数据库初体验
    MongoDB安装
    关于数据库你必须知道的事~
    PostgreSQL中的MVCC 事务隔离
    深入浅出MySQL之索引为什么要下推?
    Java集合篇:Map集合的几种遍历方式及性能测试
    Oracle11g:数据库恢复总结
  • 原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7285199.html
Copyright © 2020-2023  润新知