hdu6121 build a tree(树)

题解:

可以考虑每一层结点的子树大小

必定满足下面的情况,即

a,a,a,a,a,a,b,c,c,c,c........

然后每一层依次往上更新,结果是不变的

一共有logn层,所以依次扫上去,统计结果即可

注意到k=1的时候,是一条链,需要特殊处理orz

这个打表可以发现明显的规律,也是二进制的一种容斥吧

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
typedef long long ll;
LL n, k;
LL mypow(LL a, LL b){
    if( pow((double)a, b) > 1.5e18) return 1e18;
    LL ans = 1; for(; b; b >>= 1) { if(b&1) ans *= a; a *= a; } return ans;
}

int main()
{
    int T;
    cin>>T;
    while(T--){
        cin>>n>>k;
        if(n == 1){
            cout<<1<<endl;
            continue;
        }
        if(k == 1){
            LL t = n%4;
            if(t == 1) cout<<1<<endl;
            else if(t == 2) cout<<n+1<<endl;
            else if(t == 3) cout<<0<<endl;
            else cout<<n<<endl;
            continue;
        }
        LL d = 0, sum = 0;
        while(sum + mypow(k, d) <= n) sum += mypow(k, d), d++;
        if(sum == n){
            d--;
            LL ans = 0, sz = 1;
            while(d != -1){
                LL N = mypow(k, d);
                if(N&1) ans ^= sz;
                sz = 1+sz*k;
                d--;
            }
            cout<<ans<<endl;
            continue;
        }
        LL N = n - sum, ans = 0;
        LL X = N, L = 1, R = 0, Xv = 1, D = d;
        while(d){
            LL dL = mypow(k, d);
            ans ^= Xv;
            if((X-1)&1) ans ^= L;
            if((dL-X)&1) ans ^= R;
            LL Nl = X-1;
            LL Nx = Nl/k*k + 1, Nfx = X-Nx;
            LL Ny = Nx+k-1, Nfy = Ny-X;
            Xv = Nfx*L + Nfy*R + Xv + 1;
            if((double)L*k < 1.5e18) L = 1+L*k;
            R = 1+R*k;
            X = (Nx-1)/k + 1;
            d--;
        }
        ans ^= Xv;
        cout<<ans<<endl;
    }
}
原文地址:https://www.cnblogs.com/Saurus/p/7374713.html