題意:c++
給一顆K叉樹,統計全部子樹大小的異或和,節點數n和k都小於1e18。spa
分析:code
比賽時候一開始被公式搞懵逼了,而後隊友30分鐘就A掉了。blog
昨天本身寫了一下,哇好難寫,各類bug,何時本身的代碼能力這麼弱了- -。遞歸
其實也很簡單,由於n個節點分紅K叉樹,最後一層必然出現三種狀況。it
一種是滿K叉,一種是不滿K叉,還有一種是上一層滿叉。class
只要知道每一層,存在不滿K叉的子樹是第幾叉,而後就能推算出前面滿K叉的數量,和後面不滿K叉的數量。變量
根據異或的性質,判一下奇偶,而後ans異或左邊子樹大小(能夠預處理,也能夠遞歸時候保存)。bug
同理右邊的就是去掉一層的子樹。最後對於中間單獨不滿K叉的,用一個變量統計節點個數便可。統計
(寫的時候,各類bug。返回值沒用longlong找了一個多小時。。。
代碼很短:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 long long n, k; 5 long long ans, dep, du, pw[100]; 6 7 long long dfs(long long d, long long tol, long long lotol) { 8 dep++; 9 pw[dep - 1] = tol; 10 if(tol >= n) { 11 long long idx = lotol - tol + n - 1; 12 if((idx + 1) & 1)ans ^= 1; 13 du = idx % k + 1; 14 return idx / k; 15 } 16 long long idx = dfs( d + 1, tol + lotol * k, lotol * k); 17 du++; 18 ans ^= du; 19 if(idx & 1)ans ^= pw[dep - d]; 20 if((lotol - idx - 1) & 1)ans ^= pw[dep - d - 1]; 21 du += (idx % k) * pw[dep - d] + (k - idx % k - 1) * pw[dep - d - 1]; 22 return idx / k; 23 } 24 25 long long xor_n(long long g) { 26 long long t = g & 3; 27 if (t & 1) return t / 2 ^ 1; 28 return t / 2 ^ g; 29 } 30 31 int main() { 32 int t; 33 scanf("%d", &t); 34 while(t--) { 35 ans = dep = 0; 36 scanf("%lld%lld", &n, &k); 37 if(k == 1) { 38 printf("%lld\n", xor_n(n)); 39 continue; 40 } 41 dfs(1, 1, 1); 42 printf("%lld\n", ans); 43 } 44 return 0; 45 }