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叉树,那么直接就可以计算出结果。
当不是叶子满的时候,可以发现它的某些地方是满的。那么想办法递归处理从上到下。
将那些满的取下来计算。剩下的继续递归。
当k=1的时候递归时间超限。
从1到n取异或和可以发现前i的前缀异或和有规律4为一周期。1,+1,0,原数;

*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <iostream>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
typedef long long LL;
#define ms(x,y) memset(x,y,sizeof x)
typedef pair<int, int> P;
const LL INF = 1e10;
const int mod = 1e9 + 7;
const int maxn = 3e5 + 100;
map<LL,LL>mp;
void get(LL n,LL k,LL &h,LL &r)
{
    LL p = 1;
    if(n==1){
        h = 0, r = 0; return ;
    }
    n -= 1;
    for(int i = 1; 1; i++){
        if(n==p*k){
            h = i, r = 0; return ;
        }
        if(n/k<p){///如果判断n<=k*p,那么可能要考虑取整。
            h = i, r = n; return ;
        }
        /*if(log10(n)<log10(p)+log10(k)){
            h = i, r = n;
            return ;
        }*/
        p = p*k;
        n -= p;
    }
}
LL cal(LL h,LL k)
{
    if(h==0) return 1;
    LL p = 1;
    LL sum = 1;
    for(int i = 1; i <= h; i++){
        p *= k;
        sum += p;
    }
    return sum;
}
void work(LL num,LL h,LL k)
{
    if(num==0) return ;
    LL n = cal(h,k);
    mp[n] += num;
    n -= 1;
    while(n){
        mp[n/k] += num*k;
        n /= k;
        n -= 1;
    }
}
LL Pow(LL a,LL b)
{
    LL p = 1;
    while(b){
        if(b&1) p *= a;
        a = a*a;
        b >>= 1;
    }
    return p;
}
void solve(LL n,LL k)
{
    if(n==1){
        mp[1]++;
        return ;
    }
    LL h, r;
    get(n,k,h,r);
    if(r==0){
        work(1,h,k); return ;
    }
    if(h==1){
        mp[n] += 1;
        mp[1] += n-1;
        return ;
    }
    LL p = Pow(k,h-1);
    LL num;
    if(r%p==0) num = r/p;
    else num = r/p+1;
    work(num-1,h-1,k);
    work(k-num,h-2,k);
    mp[n]++;
    solve(n-(num-1)*cal(h-1,k)-(k-num)*cal(h-2,k)-1,k);

}
void test()///k=1时候的规律。
{
    for(int i = 1; i <= 20; i++){
        printf("%d: ",i);
        int ans = 0;
        for(int j = 1; j <= i; j++){
            ans ^= j;
        }
        printf("%d\n",ans);
    }
}
int main()
{
    //freopen("YYnoGCD.in","r",stdin);
    //freopen("YYnoGCD.out","w",stdout);
    //freopen("in.txt","r",stdin);
    int T;
    //test();
    LL n, k;
    cin>>T;
    while(T--)
    {
        scanf("%lld%lld",&n,&k);
        LL ans = 0;
        if(k==1){
            if(n%4==0) ans = n;
            if(n%4==1) ans = 1;
            if(n%4==2) ans = n+1;
            if(n%4==3) ans = 0;
        }else{
            k = min(k,n-1);
            mp.clear();
            solve(n,k);
            map<LL,LL>::iterator it;
            for(it = mp.begin(); it!=mp.end(); it++){
                if((it->second)%2){
                    ans ^= it->first;
                }
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
时间: 2024-10-03 16:35:07

hdu6121 Build a tree 模拟的相关文章

【暴力】hdu6121 Build a tree

给你n,K,让你构造出一颗n个结点的完全K叉树,求所有结点子树大小的异或和. 先把n号结点到根的路径提取出来单独计算.然后这条路径把每一层分成了左右两部分,每一层的左侧和其上一层的右侧的结点的子树大小相同. 就可以容易计算每种大小的子树个数了. 当K等于1时,要单独讨论,答案为1 xor 2 xor ... xor n.这个打个表非常明显. #include<cstdio> using namespace std; typedef long long ll; ll n,K,pw[105]; i

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 —— 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

easyui Tree模拟级联勾选cascadeCheck,节点选择,父节点自动选中,节点取消,父节点自动取消选择,节点选择,所有子节点全部选择,节点取消,所有子节点全部取消勾选

最近项目中用到easyui tree,发现tree控件的cascadeCheck有些坑,不像miniui 的tree控件,级联勾选符合业务需求,所以就自己重新改写了onCheck事件,符合业务需求.网上百度了很多资料,都没有完全符合自己业务场景的,所以就自己动手写咯. 先说一下自己的业务需求: 1.选中节点,上级以及所有直系上级节点自动选中,所有下级子孙节点全部自动选中: 2.取消选择节点,如果兄弟节点都未选择,则上级以及所有直系上级节点自动取消选择,所有下级子孙节点全部取消选中. 这里说一下c

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

Build Relationship Tree

import java.util.*; class Node{ String val; Set<Node> children = new HashSet<Node>(); // at most 15 children; public Node(String val){ this.val = val; this.children = new HashSet<>(); } } public class RelationTree { private void travel(N

Verify Preorder Serialization of a Binary Tree

One way to serialize a binary tree is to use pre-order traversal. When we encounter a non-null node, we record the node's value. If it is a null node, we record using a sentinel value such as #. _9_ / 3 2 / \ / 4 1 # 6 / \ / \ / # # # # # # For examp

10.27 模拟赛

这一次终极被吊打 甚至没进前十 T2 最后改错 T3 没写正解 T1 elim 题目大意: n 行 m 列的游戏棋盘,一行或一列上有连续 三个或更多的相同颜色的棋子时,这些棋子都被消除 当有多处可以被消除时,这些地方的棋子将同时被消除 求消除后的棋盘 思路: sb模拟 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cm

源廓Pulsonix 8.5 Build 5905 PCB电路板设计工具

Pulsonix 8.5 Build 5905 PCB电路板设计工具 Pulsonix 7.5 1CD Pulsonix 8.5 Build 5905除了修复了一些已知的一些错误,最新版本包含Report Maker功能的几个新 增功能,其中包括帮助最终检查过程的新命令: "PCB面板起源"用于报告在PCB设计中的位置,用于将其定位在面板内. "Line Width",电路板轮廓.面板轮廓.切口或段的"线宽". "Board Centr