HDU 6121 Build a tree(找规律+模拟)

Build a tree

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 946    Accepted Submission(s): 369

Problem Description

HazelFan wants to build a rooted tree. The tree has n nodes labeled 0 to n−1, and the father of the node labeled i is the node labeled ⌊i−1k⌋. HazelFan wonders the size of every subtree, and you just need to tell him the XOR value of these answers.

Input

The first line contains a positive integer T(1≤T≤5), denoting the number of test cases.
For each test case:
A single line contains two positive integers n,k(1≤n,k≤1018).

Output

For each test case:
A single line contains a nonnegative integer, denoting the answer.

Sample Input

2
5 2
5 3

Sample Output

7
6

Source

2017 Multi-University Training Contest - Team 7

/*
* @Author: lyuc
* @Date:   2017-08-15 14:04:25
* @Last Modified by:   lyuc
* @Last Modified time: 2017-08-16 22:11:31
*/

/*
 题意:给你一个n个节点的k叉树,然后让你求每个子树节点个数的异或和

 思路:
     当k等于1的时候处理会超时的,但是有规律:
         n%4=0    结果为n
         n%4=1    结果为1
         n%4=2    结果为n+1
         n%4=3    结果为0
     当n<=k+1时:
         如果      n%2==1
        结果      n

        如果      n%2==0
        结果      n+1
    如果是个完全k叉树:
        如果     k%2==0
        结果     n 

        如果     k%2==1
        结果     每层异或一个
    剩余的情况中:
        root节点的子树中最多只有一个子树是不完全k叉树,这棵树单独处理,然后剩下的是满k叉树
    按照上面的办法求

*/

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>

#define LL long long
#define INF 0x3f3f3f3f
#define MAXN 105

using namespace std;

int t;
LL n,k;
LL res;
LL num[MAXN];

inline void init(){
    res=0;
}

int main(){
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    scanf("%d",&t);
    while(t--){
        init();
        scanf("%lld%lld",&n,&k);
        if(n<=k+1){//如果是矩阵上三角
            if(n%2==1){
                printf("%lld\n",n);
            }else{
                printf("%lld\n",n+1);
            }
        }else{
            if(k==1){//k=1的时候需要特殊处理
                switch(n%4){
                    case 0:
                        printf("%lld\n",n);
                        break;
                    case 1:
                        puts("1");
                        break;
                    case 2:
                        printf("%lld\n",n+1);
                        break;
                    case 3:
                        puts("0");
                        break;
                }
            }else{
                //判断是不是完全树
                LL deepth=1;//树的深度(不包括最后一行,根节点深度为0)
                LL cur=1;
                bool flag=false;
                num[1]=1;
                while(num[deepth]<n){
                    deepth++;
                    cur*=k;
                    num[deepth]=num[deepth-1]+cur;//计算出根节点到每层的节点数
                    if(num[deepth]==n){
                        flag=true;
                        break;
                    }
                }
                if(flag==true){//如果是完全树
                    if(k%2==0){//偶数叉树,异或到最后只是一个根节点了
                        printf("%lld\n",n);
                    }else{//奇数叉树,异或到最后每层剩一个节点
                        cur=1;
                        while(cur<n){
                            res^=cur;
                            cur*=k;
                        }
                        printf("%lld\n",res);
                    }
                }else{//如果不是完全树
                    // 整棵树
                    res = n;

                    // 最底层单独做
                    res ^= (n - num[deepth-1]) & 1;

                    --deepth;
                    LL p = (n - 2) / k; // [(n - 1) - 1] / k,倒数第 2 层开始
                    LL lid, rid, lnum, rnum, lch;
                    for(LL d = 2; p > 0; p = (p - 1) / k, ++d, --deepth)
                    {
                        // 当前层最左边结点的标号
                        lid = num[deepth-1];

                        // 当前层最右边结点的标号
                        rid = num[deepth] - 1;

                        // 左边的子树(满的)的大小
                        lnum = num[d];

                        // 右边的子树(少一层,但也是满的)的大小
                        rnum = num[d - 1];

                        if((p - lid) & 1)
                            res ^= lnum;

                        if((rid - p) & 1)
                            res ^= rnum;

                        lch = p; // p 为根的子数最左小角的后代结点

                        while(lch <=(n - 2) / k) // lch * k + 1 <= n - 1
                            lch = lch * k + 1;

                        res ^= num[d-1] + n - lch;
                    }
                    printf("%lld\n",res);
                }
            }
        }
    }
    return 0;
}
时间: 2024-10-06 08:42:51

HDU 6121 Build a tree(找规律+模拟)的相关文章

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

HDU 6121 Build a tree —— 2017 Multi-University Training 7

HazelFan wants to build a rooted tree. The tree has nn nodes labeled 0 to n?1, and the father of the node labeled i is the node labeled  . HazelFan wonders the size of every subtree, and you just need to tell him the XOR value of these answers. Input

HDU 4572 Bottles Arrangement(找规律,仔细读题)

题目 //找规律,123321123321123321…发现这样排列恰好可以错开 // 其中注意题中数据范围: M是行,N是列,3 <= N < 2×M //则猜测:m,m,m-1,m-1,m-2,m-2,……,2,2,1,1求出前m个数字的和就是答案. //发现案例符合(之前的代码第二天发现案例都跑不对,真不知道我当时眼睛怎么了) #include <iostream> #include<stdio.h> #include<string.h> #inclu

HDU 2147-kiki&#39;s game(博弈/找规律)

kiki's game Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 40000/10000 K (Java/Others) Total Submission(s): 9174    Accepted Submission(s): 5485 Problem Description Recently kiki has nothing to do. While she is bored, an idea appears in his

洛谷 P1014 Cantor表【蛇皮矩阵/找规律/模拟】

题目描述 现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的.他是用下面这一张表来证明这一命题的: 1/1 1/2 1/3 1/4 1/5 … 2/1 2/2 2/3 2/4 … 3/1 3/2 3/3 … 4/1 4/2 … 5/1 … … 我们以Z字形给上表的每一项编号.第一项是1/1,然后是1/2,2/1,3/1,2/2,… 输入输出格式 输入格式: 整数N(1≤N≤10000000) 输出格式: 表中的第N项 输入输出样例 输入样例#1: 复制 7 输出样例#1: 复

8/2 multi4 E找规律+模拟,空间开小了然后一直WA。。。J爆搜check不严谨WA。。。multi3 G凸包判共线写错数组名???样例太好过.想哭jpg。

multi4 Problem E. Matrix from Arrays 题意:构造一个数组,求子矩阵前缀和. 思路:打表找规律,"发现"L为奇数时循环节为L,为偶数时循环节为2L,求相应循环节的二维前缀和然后加加减减计算一下就好. 虚伪地证明一下循环节:L为奇数时对于第x行/列开始的位置有(x  +  x+L-1)*L/2   ->     (2x+L-1)/2(为整数)*L,因此扫过L行/列也就扫过了L整数倍"(2x+L-1)/2"倍的A[0]~A[L],

HDU 5703 Desert 水题 找规律

已知有n个单位的水,问有几种方式把这些水喝完,每天至少喝1个单位的水,而且每天喝的水的单位为整数.看上去挺复杂要跑循环,但其实上,列举几种情况之后就会发现是找规律的题了= =都是2的n-1次方,而且这题输出二进制数就行了......那就更简单了,直接输出1,然后后面跟n-1个0就行了╮(╯_╰)╭ 下面AC代码 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm>

HDU 5793 A Boring Question (找规律 : 快速幂+乘法逆元)

A Boring Question Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 865    Accepted Submission(s): 534 Problem Description There are an equation.∑0≤k1,k2,?km≤n∏1?j<m(kj+1kj)%1000000007=?We define

HDU - 4722 Good Numbers 【找规律 or 数位dp模板】

If we sum up every digit of a number and the result can be exactly divided by 10, we say this number is a good number. You are required to count the number of good numbers in the range from A to B, inclusive. InputThe first line has a number T (T <=