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

The first line contains a positive integer T(1≤T≤5)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)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

题意:画一下题目介绍的树,发现这是一个k叉树,那么题目要求所有子树大小的异或和。思路:我们从序号为n的节点开始,往上求异或和。n计算到某一层时,对于处在n节点左边的节点(子树),它们是t+1层的满k叉树,在右边的节点(子树)是t层的满二叉树,满二叉树的大小可以通过打表得到。根据异或计算的性质,大小相同的子树进行异或,有奇数个进行异或时结果为该子树的大小,偶数个时为0。而对n位置节点的子树来说,不是满二叉树就是非满二叉树,而且在计算这个子树大小时一旦它在某一层是非满二叉树,接下来往上它就一直是非满二叉树。还有,k==1时特判一下。具体实现参看代码。

AC代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long LL;
LL n, k;
LL num[100];
int main()
{
    int T;
    cin>>T;
    num[0]=1;
    while(T--)
    {
        scanf("%lld %lld", &n, &k);
        if(k==1){
            if(n==1)
                printf("%d\n", 1);
            else if(n==2)
                printf("%d\n",3);
            else if(n==3)
                printf("%d\n", 0);
            else
            {
                int k=n%4;
                if(k==0)
                    printf("%lld\n", n);
                else if(k==1)
                    printf("%d\n", 1);
                else if(k==2)
                    printf("%lld\n", n+1);
                else
                    printf("%d\n", 0);
            }
            continue;
        }
        n--;
        int level=0,t=0;
        LL lm=0, rm=0;
        while(rm<n){
            t++;
            lm=rm+1;
            rm=lm*k;
            num[t]=rm+1;
        }
        LL res=0,left,right,s=n+1,m;
        t=0;
        bool flag=0;
            LL mid=n%k;//mid判断是否为满k叉树, m为非满k叉树的大小
            left=n-mid-lm+1;
            //cout<<left<<endl;
            if(left&1){
                res^=num[0];
            }
            if(mid&1)
                res^=num[0];
            if(mid)
                flag=1;

            m=(n-(n-1)/k*k)*num[0]+1;
            //cout<<m<<endl;
            while(n)
            {

                //cout<<res<<‘*‘<<endl;

                t++;
                //cout<<t<<‘ ‘<<m<<endl;

                n=(n-1)/k;
                if(n<=0)
                    break;

                mid=n%k;
                lm=(lm-1)/k;
                rm=(rm-1)/k;
                //cout<<lm<<‘ ‘<<n<<‘ ‘<<rm<<endl;
                right=rm-n;
                left=n-lm+1;
                if(flag||mid){
                    flag=1;
                    left--;
                    res^=m;
                }

                if(left&1)
                    res^=num[t];
                if(right&1)
                    res^=num[t-1];
                m+=(n-(n-1)/k*k-1)*num[t]+(((n-1)/k+1)*k-n)*num[t-1]+1;

            }
        res^=s;
        printf("%lld\n", res);
    }
    return 0;
}

				
时间: 2024-10-12 00:04:03

HDU 6121 Build a tree —— 2017 Multi-University Training 7的相关文章

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

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 6170 - Two strings | 2017 ZJUT Multi-University Training 9

/* HDU 6170 - Two strings [ DP ] | 2017 ZJUT Multi-University Training 9 题意: 定义*可以匹配任意长度,.可以匹配任意字符,问两串是否匹配 分析: dp[i][j] 代表B[i] 到 A[j]全部匹配 然后根据三种匹配类型分类讨论,可以从i推到i+1 复杂度O(n^2) */ #include <bits/stdc++.h> using namespace std; const int N = 2505; int t;

hdu6121 Build a tree 模拟

/** 题目:hdu6121 Build a tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6121 题意:n个点标号为0~n-1:节点i的父节点为floor((i-1)/k); 0是根节点. 求这个树的所有节点为根的子树的节点数的异或和. 思路:模拟 可以发现k = min(k,n-1):即:k>=n-1时候结果一样. 然后画图可以发现是一个满k叉树(叶子不一定满). 然后发现:如果这是一个叶子也满的k叉树,那么直接就可以计算出结果. 当不

HDU 4107 Gangster Segment Tree线段树

这道题也有点新意,就是需要记录最小值段和最大值段,然后成段更新这个段,而不用没点去更新,达到提高速度的目的. 本题过的人很少,因为大部分都超时了,我严格按照线段树的方法去写,一开始居然也超时. 然后修补了两个地方就过了,具体修改的地方请参看程序. 知道最大值段和最小值段,然后修补一下就能过了.不是特别难的题目. #include <stdio.h> #include <string> #include <algorithm> using namespace std; c

hdu 4896 Minimal Spanning Tree

Minimal Spanning Tree Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 144    Accepted Submission(s): 44 Problem Description Given a connected, undirected, weight graph G, your task is to select

hdu 5378 Leader in Tree Land(dp+逆元)

题目链接:hdu 5378 Leader in Tree Land 问题可以理解成N个节点的树,有K个ministers的概率,最后乘上N!.每个节点为ministers的概率即为1 / son(以该节点为根节点的子树包含的节点个数),同样不为ministers的概率为(son-1)/son.所以没有必要考虑树的结构,直接根句子节点的个数转移dp[i][j] dp[i][j] = dp[i-1][j-1] * 1 / son[u] dp[i][j] = dp[i-1][j] * (son[u]-

HDU 4896 Minimal Spanning Tree(矩阵快速幂)

题意: 给你一幅这样子生成的图,求最小生成树的边权和. 思路:对于i >= 6的点连回去的5条边,打表知907^53 mod 2333333 = 1,所以x的循环节长度为54,所以9个点为一个循环,接下来的9个点连回去的边都是一样的.预处理出5个点的所有连通状态,总共只有52种,然后对于新增加一个点和前面点的连边状态可以处理出所有状态的转移.然后转移矩阵可以处理出来了,快速幂一下就可以了,对于普通的矩阵乘法是sigma( a(i, k) * b(k, j) ) (1<=k<=N), 现在

hdu 4603 Color the Tree 2013多校1-4

这道题细节真的很多 首先可以想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占领和这个点邻接的边 所以,解决这道题的步骤如下: 预处理阶段: step 1:取任意一个点为根节点,找出父子关系并且对这个树进行dp,求出从某个节点出发往下所包含的所有边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点,从某条边出发所包含的边的综合,并且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每个点的