• HDU 6121 Build a tree(完全K叉树)


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

    题意:
    给你一颗完全K叉树,求出每棵子树的节点个数的异或和。

     

    思路:

    首先需要了解一些关于完全K叉树或满K叉树的一些知识:

    对于每棵子树,只有三种情况:

    ①是满K叉树  ②不是满K叉树  ③叶子节点

    并且非满K叉树最多只有一个,所以只需要将它进行特殊处理,具体看代码吧,说不清楚。代码参考了http://blog.csdn.net/my_sunshine26/article/details/77200282

    当K=1时,树是链状的,需要打表找规律!

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<sstream>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 #include<map>
    11 #include<set>
    12 using namespace std;
    13 typedef long long ll;
    14 typedef pair<int,ll> pll;
    15 const int INF = 0x3f3f3f3f;
    16 const int maxn=100+5;
    17 
    18 ll n, k, ans;
    19 ll num[maxn];
    20 int depth;
    21 
    22 void init()
    23 {
    24     num[0]=0;
    25     for(int i=1;i<=depth;i++)
    26     {
    27         num[i]=num[i-1]+pow((long double)k,(long double)i-1);  //因为pow默认是pow(int,int),没有对应long long的,所以我这儿用long double来代替了一下
    28     }                                                          //当然这里可以自己用快速幂来计算
    29 }
    30 
    31 int main()
    32 {
    33     //freopen("in.txt","r",stdin);
    34     int T;
    35     scanf("%d",&T);
    36     while(T--)
    37     {
    38         scanf("%I64d%I64d",&n,&k);
    39         if(k==1)                  //特判
    40         {
    41             ll tmp=n%4;
    42             if(tmp==0) ans=n;
    43             else if(tmp==1) ans=1;
    44             else if(tmp==2) ans=n+1;
    45             else ans=0;
    46             printf("%I64d
    ",ans);
    47             continue;
    48         }
    49 
    50         depth=1;
    51         ll tmp=n-1;
    52         //计算树的深度
    53         while(tmp>0)
    54         {
    55             tmp=(tmp-1)/k;
    56             depth++;
    57         }
    58         init(); //预处理前i层的节点个数
    59         ans=0;
    60         ans^=(n-num[depth-1])&1; //先处理一下最后一层
    61         depth--;
    62         ll now=2;  //当前从下往上第几层
    63         ll pos=(n-1-1)/k;
    64         while(depth>0)
    65         {
    66             ll left=num[depth-1];  //当前层数最左边编号
    67             ll right=num[depth]-1; //当前层数最右边编号
    68             ll tmp1=num[now];      //左边树大小
    69             ll tmp2=num[now-1];    //右边树大小
    70             
    71             //奇数才有贡献
    72             if((pos-left)&1)   ans^=tmp1;
    73             if((right-pos)&1)  ans^=tmp2;
    74 
    75             ll cnt=pos;
    76             while(cnt<=(n-1-1)/k)  cnt=cnt*k+1;
    77             ans^=(num[now-1]+n-cnt);  //单独处理临界点子树
    78             now++;
    79             depth--;
    80             pos=(pos-1)/k;
    81 
    82         }
    83         printf("%I64d
    ",ans);
    84     }
    85     return 0;
    86 }
  • 相关阅读:
    BZOJ 2821: 作诗(Poetize)( 分块 )
    BZOJ 2440: [中山市选2011]完全平方数( 二分答案 + 容斥原理 + 莫比乌斯函数 )
    BZOJ 1058: [ZJOI2007]报表统计( 链表 + set )
    BZOJ 1034: [ZJOI2008]泡泡堂BNB( 贪心 )
    BZOJ 1016: [JSOI2008]最小生成树计数( kruskal + dfs )
    BZOJ 2329: [HNOI2011]括号修复( splay )
    BZOJ 3143: [Hnoi2013]游走( 高斯消元 )
    BZOJAC400题留念
    BZOJ 2982: combination( lucas )
    poj 3233
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/7376427.html
Copyright © 2020-2023  润新知