zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
  • 相关阅读:
    自动化运维工具Ansible实战Playbooks剧本使用
    Mysql5.6.x版本半同步主从复制的开启方法
    mysql数据库的一些基本概念
    mysql之视图
    mysql之索引
    机器学习笔记09-----决策树与随机森林1---决策树概述
    机器学习笔记08-----回归2
    Anaconda 利用conda安装第3方包
    机器学习笔记07-----回归1
    使用navicat导出数据库字典
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7384130.html
Copyright © 2011-2022 走看看