zoukankan      html  css  js  c++  java
  • 2017多校第7场 HDU 6121 Build a tree K叉树,思维

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6121

    题意:一个n个点的完全k叉树,求每个节点的size的异或和。

    解法:容易发现,考虑根的所有孩子,最多只有一个不是满k叉树,我们只要把这个子节点作为临界点,其左边的就是满k叉树,其右边的便是比左边层数小一的满k叉树,那么我们每次只要算出中间这个非满k叉树的节点个数即可,然后对这个孩子进行递归处理。而其他子树由于是满k叉树,其数量可以提前预处理出来。这样处理在k>2的时候复杂度是logk(n)的,但是当k等于1时速度很慢会T,所以直接特判k=1的情况。

    //HDU 6121
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    LL n, k, ans, num[105];
    LL qsm(LL a, LL n){
        LL ret=1;
        while(n){
            if(n&1) ret=ret*a;
            a=a*a;
            n>>=1;
        }
        return ret;
    }
    void init(LL k, LL dep)
    {
        for(int i=1; i<=dep; i++){
            num[i] = (qsm(k,i)-1)/(k-1);
        }
    }
    int main()
    {
        int T;
        scanf("%d", &T);
        //freopen("1.in","r",stdin);
        while(T--)
        {
            scanf("%lld%lld", &n,&k);
            if(k == 1){
                LL temp=n%4;
                if(temp==0) printf("%lld
    ", n);
                else if(temp==1) printf("%lld
    ",1LL);
                else if(temp==2) printf("%lld
    ", n+1);
                else printf("%lld
    ", 0LL);
                continue;
            }
            int dep = 1;//树高
            LL res=n-1;
            while(res){
                res=(res-1)/k;
                dep++;
            }
            init(k,dep);
            ans = n; //根节点为0的子树
            ans ^= (n-num[dep-1])&1;//最后一层有多少个节点
            dep--;
            LL pos=(n-1-1)/k;//临界点在当前层标号为pos的子树上
            int now = 2;//从下往上第几层,最后一层已经处理了
            while(dep>1){
                LL left=num[dep-1];//当前层最左边节点的编号
                LL right=num[dep]-1;//当前层最右边的节点的编号
                LL temp1=num[now];//当前层满k叉树的子节点个数
                LL temp2=num[now-1];//当前层满k叉数层数减1后的子节点个数
                if((pos-left)&1){
                    ans^=temp1;
                }
                if((right-pos)&1){
                    ans^=temp2;
                }
                LL cnt=pos;
                while(cnt<=(n-1-1)/k){//cnt*k+1<=n-1会爆long long
                    cnt=cnt*k+1;
                }
                ans ^= num[now-1]+n-cnt;//当前点的子树特殊处理
                now++;
                dep--;
                pos=(pos-1)/k;
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    Java使用Preconditions.checkNotNull(.....)判空对象, 并处理可能的NullPointerException异常
    jdk1.8
    BigDecimal
    BIOS的启动原理学习--加载引导程序
    Linux系统想要切换到root用户时出现authentication failure
    Ubuntu Linux 操作系统与实验教程--Linux系统的基本组成
    Java中“==”和equals()的区别
    自己编写操作系统2--初始镜像编写以及VM启动
    关于Windows下子系统WSL的思考
    自己编写操作系统1--概述
  • 原文地址:https://www.cnblogs.com/spfa/p/7372420.html
Copyright © 2011-2022 走看看