Problem Description
HazelFan wants to build a rooted tree. The tree has n nodes
labeled 0 to n−1,
and the father of the node labeled i is
the node labeled ⌊i−1k⌋.
HazelFan wonders the size of every subtree, and you just need to tell him the XOR value of these answers.
Input
The first line contains a positive integer T(1≤T≤5),
denoting the number of test cases.
For each test case:
A single line contains two positive integers n,k(1≤n,k≤1018).
For each test case:
A single line contains two positive integers n,k(1≤n,k≤1018).
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
A single line contains a nonnegative integer, denoting the answer.
Sample Input
2 5 2 5 3
Sample Output
7 6
题目大意:给你个完全k叉树,有n个节点,要你求出所有子树的大小的异或结果。
第一眼看上去,不知所措,后来分析了一下,每一层有三种情况,满二叉树,不满的,满二叉树但是属于上一层的,最后一层处理一下,得到三种情况的结果,接着就可以一层一层向上面求。
但是还有一个很重要的问题,导致我的代码调了一个晚上,就是:算最后一层的时候,可能会出现溢出的问题,如何解决呢,我们就只计算到倒数第二层,然后用总数n减去前面的部分的和,就得到最后一层的数字,然后就可以接着处理了
ps:long long 的数据范围大概是-10^19~10^19
最后贴一下最后的ac代码
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<stack>
#define ll long long
#define read(a) scanf("%d",&a);
using namespace std;
ll sz[110];
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)
ans*=a;
a*=a;
b>>=1;
}
return ans;
}
void table(ll k,ll deepth){
ll sum=1;
for(ll i=1;i<deepth;i++){
sum+=qpow(k,i);
sz[i]=sum;
//printf("%lld %lld\n",i,sz[i]);
}
}
int main(){
freopen("test.txt","r",stdin);
int t;
scanf("%d",&t);
while(t--){
ll n,k;
scanf("%lld %lld",&n,&k);
if(k==1){
ll num=n%4;
ll ans=0;
if(num==0){
ans=n;
}
else if(num==1){
ans=1;
}
else if(num==2){
ans=n+1;
}
else if(num==3){
ans=0;
}
printf("%lld\n",ans);
continue;
}
ll cnt1,cnt2,cnt3;
ll cnt2_left;
ll deepth;
ll m=n-1;
ll ans=0;
ll size1,size2,size3;
sz[0]=1;
deepth=0;
while(m){
deepth++;
m=(m-1)/k;
}
//printf("%lld\n",deepth);
table(k,deepth);
ll left=n-sz[deepth-1];
cnt1=left/k;
if(left%k){
cnt2=1;
cnt2_left=left%k;
}
else{
cnt2=0;
cnt2_left=0;
}
cnt3=sz[deepth-1]-sz[deepth-2]-cnt1-cnt2;
if(left%2)
ans^=1;
//printf("%lld %lld %lld %lld %lld %lld\n",cnt1,cnt2,cnt3,cnt2_left,left,ans);
ll deep=deepth-1;
while(deep>=0){
if(cnt2_left>0){
size2=sz[deepth-deep-1]+cnt2_left;
ans^=size2;
}
if(cnt1>0){
size1=sz[deepth-deep];
if(cnt1%2)
ans^=size1;
ll num=cnt1%k;
cnt2_left+=num*(size1-sz[deepth-deep-1]);
cnt1/=k;
}
if(cnt3>0){
size3=sz[deepth-deep-1];
if(cnt3%2)
ans^=size3;
cnt3/=k;
}
deep--;
}
printf("%lld\n",ans);
}
return 0;
}