1. 程式人生 > >hdu6121 Build a tree 模擬

hdu6121 Build a tree 模擬

題目 get -1 前綴 思路 n-1 void span oid

/**
題目: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\n",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; }

hdu6121 Build a tree 模擬