https://www.luogu.com.cn/problem/CF1237E
對 https://www.luogu.com.cn/article/fd9qi7ie 的一些補充。
step1:容易發現根的奇偶性和 \(n\) 的奇偶性相同。所以根的右子樹大小一定是偶數。
step2:一顆合法的樹,滿足根的左右子樹也是合法的樹。
step3:\(2^k - 1\) 顯然是奇數,所以一顆滿二叉樹(除了只有一個點的樹)一定是不合法的。
step4:一個合法的樹,根的左右子樹也都是合法的樹。
考慮兩個合法的樹合併為一個合法的樹。
題目中要求每個點到根的距離的和最小,也就是樹是一顆滿二叉樹在最後一層刪除一些點得到。所以那兩個合法的樹必須高度相同為 \(i\)(如果不同,第一種情況是其中一棵樹是滿二叉樹,這不合法,第二種情況反之,這樣合併出來的樹不合法)。
設 \(f_i\) 表示深度為 \(i\) 的合法的樹的最小大小。對於 \(i \le 2\) 先特判掉。
接下來需要證明深度為 \(i(i \ge 3)\) 的合法的數的大小值有且只有可能 \(f_i\) 或 \(f_i+1\)。考慮歸納法證明:
- 對於 \(i=3\) 成立(暴推驗證)。設根左子樹大小為 \(L\),根右子樹大小為 \(R\)。
- \(R\) 只能是偶數,而 \(L\) 也只能是 \(f_{i-1}\) 或 \(f_{i-1}+1\)。
順便也得出了轉移式 \(f_i = 2 \times f_{i-1} + 1 + [f_{i-1} \bmod 2 = 1]\)。
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int n, f[30];
int main(){
cin >> n;
if(n == 1 || n == 2 || n == 4 || n == 5){
cout << 1;
return 0;
}else if(n == 3){
cout << 0;
return 0;
}
f[3] = 4;
for(int i = 4; i <= 25; i++){
f[i] = 2 * f[i - 1] + 1 + (f[i - 1] % 2 == 1);
if(f[i] == n || f[i] + 1 == n){
cout << 1;
return 0;
}
}
cout << 0;
return 0;
}