HDU_6121 Build a tree 【DFS&&位运算技巧】

题目链接

题目描述

给定一个n, k。建一颗k叉树,有n个节点。这棵树节点的值代表这棵树子节点的个数加上本身的节点总数之和。求所有节点值的异或。
Limit n和k都是 1e18 的范围。

解题思路

根据数据的大小,可以知道肯定不是直接递归来求的答案。
分两种情况:

  • k为1的时候,为求 1 ~ n的异或,如果一个一个异或肯定超时,这里有个规律,见代码部分,函数可以直接求处1 ~ n 的异或值。
  • k > 1时。我们可以通过给的节点来创建树,不难发现,这棵树中只有一颗是一个不满的k叉树,这棵树左边都为满k叉树,右边的也是满k叉树,比右边的会少一层。这样我们就可以直接求出左右满k叉树的异或值然后再异或上不满足k叉树的那棵树即可。不满足k叉树的我们就可以递归进行计算。每次通过递归来计算不满k叉树的左右满k叉树的数量以及其异或值。因为当k大于1时,最多递归的次数也不会超过100次,所以时间肯定是够的。
  • 最后,奇数个n异或的值相当于n,偶数个n异或为0。

代码部分

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
///计算1 ~ n的 异或值
ll ans;
inline ll Xor(ll n)
{
    return n%4==1?1:(n%4==2?n+1:(n%4==3?0:n));
}
void dfs(ll n, ll k)
{
    if(n - 1 <= k)
    {
        if(!(n & 1)) ans ^= 1;
        return;
    }
    ll cnt = 1, sum = 1;
    while(sum + cnt * k < n)
    {
        cnt *= k;
        sum += cnt;
    }
    ll l = (n - sum - 1) / cnt;
    ll r = k - 1 - l;
    if(l & 1) ans ^= sum;
    if(r & 1) ans ^= (sum - cnt);
    n -= (1 + l * sum + r * (sum - cnt));
    ans ^= n;
    dfs(n, k);
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    cin >> t;
    while(t --)
    {
        ll n, k;
        cin >> n >> k;
        if(k == 1)
        {
            cout << Xor(n) << endl;
        }
        else
        {
            ans = n;
            dfs(n, k);
            cout << ans << endl;
        }
    }
    return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值