• 【2017 Multi-University Training Contest


    【链接】点击打开链接


    【题意】


    询问n个点的完全k叉树,所有子树节点个数的异或总和为多少。

    【题解】


    考虑如下的一棵k=3叉树,假设这棵树恰好有n个节点.


    因为满的k叉树,第i层的节点个数为k^(i-1);

    则我们找到最大的d;

    使得

    k^0+k^1+..+k^(d-1) <=n

    自此,我们会发现,整棵树可以分成若干个树的深度大小d和d-1满k叉树

    如上图,d=3,两个圈起来的,就是一个深度为3的满k叉树和一个深度为2的满k叉树

    当然,还可能会有一个子树,它不是满的k叉树

    如上图中没有被圈出来的部分.

    深度大小为d的满k叉树的个数,可以用rest = n-(k^0+k^1+..+k^(d-1))算出来;

    它的个数就是rest/num[d],(其中num[d]表示第d层的满k叉树的节点个数.)

    就是每num[d]个最下边的那些点可以将一个深度为d-1的满k叉树组成深度为d的满k叉树

    然后看看rest%num[d]是不是为0.

    如果不为0的话,就会有一棵子树不是满k叉树;

    则肯定还有k-rest/num[d]-1棵是深度为d-1的满k叉树

    然后思考那个不是满k叉树的

    会发现.那棵子树的问题。仍然是我们最开始面临的问题

    可以递归解决的!

    获取那个子树的大小,然后递归解决就好!

    (深度为d和深度为d-1的满k叉树的子树异或和,单独写一个dfs来做就好)

    (不要忘记有多个子树,所以对应的答案要异或和子树的个数对应次数)

    k=1的情况要单独处理。找规律就好。就是1^2^3..^n的值。。

    (要注意根节点的儿子不够k个的情况。。那个时候就不用递归了,直接处理答案)



    【错的次数】


    0

    【反思】


    编程比较难。思路不难想。

    【代码】

    #include <bits/stdc++.h>
    using namespace std;
    #define rep1(i,a,b) for (int i = a;i <= b;i++)
    #define rep2(i,a,b) for (int i = a;i >= b;i--)
    #define ri(x) scanf("%d",&x)
    #define rl(x) scanf("%lld",&x)
    #define oi(x) printf("%d",x)
    #define ol(x) printf("%lld",x)
    #define os(x) printf(x)
    #define LL long long
    
    LL k,num[100],tot[100],ans;
    
    LL f(LL x,LL y){
        if (y&1)
            return x;
        else
            return 0;
    }
    
    LL dfs(int d){
        LL now = 0,temp = 0;
        rep2(i,d,1){
            temp = temp*k + 1;
            now ^= f(temp,num[i]);
        }
        return now;
    }
    
    void solve(LL n){
        num[1] = 1,tot[1] = 1;
        int d = 1;
        while (1){
            d++;
            num[d] = num[d-1]*k;
            tot[d] = tot[d-1]+num[d];
            if (tot[d]>n) break;
        }
        d--;
        LL numdp1 = 0,numd = 0,rest = n-tot[d];
        if (d == 1 && rest <= k){
            ans ^= f(1,rest);
            ans ^= n;
            return;
        }
        numdp1 = rest/num[d],numd = k - numdp1 - 1;
        LL trest = rest%num[d];
    
        ans ^= f(dfs(d),numdp1);
    
        LL temp1 = dfs(d-1);
        ans ^= f(temp1,numd);
    
        if (trest==0)
            ans ^= temp1;
         else
            solve(trest+tot[d-1]);
    
        ans ^= n;
    }
    
    int main(){
        //freopen("D:\rush.txt","r",stdin);
        int T;
        ri(T);
        while (T--){
            LL n;
            rl(n),rl(k);
            ans = 0;
            if (k==1){
                n--;
                if (n%4==0) ans = 1;
                if (n%4==1) ans = n + 2;
                if (n%4==2) ans = 0;
                if (n%4==3) ans = n+1;
            }else
                solve(n);
            ol(ans);puts("");
        }
        return 0;
    }
    
    
    


  • 相关阅读:
    VBA操作IE
    Eclipse中Git图标表示内容
    sqldeveloper更改语言设定
    VBA-FileToFileUpdate
    VBA-UTF-8文件的操作
    Null项目参与排序
    阿里云的学生机如何开放全部端口
    .net core3.1 webapi + vue + element-ui upload组件实现文件上传
    .net core控制台使用log4net
    vue2.x中使用三元表达式绑定class的时候遇到的坑
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7626049.html
Copyright © 2020-2023  润新知