题意
要求构建一个 \(n\) 个节点的二叉树,其中叶子结点被称为“源”,要求每个节点的左右子树中最深的叶子节点深度相差不超过 \(1\),问两个叶子结点深度差的最大值,\(T\) 组询问。
\(n\le10^{10000},T\le50\)。
思路
令根节点深度为 \(1\)。
设 \(f_i\) 表示最深的“源”深度为 \(i\) 的“源”最少所需的节点数。\(f_i=f_{i-1}+f_{i-2}+1\),即新增一个根结点,左子树方深度为 \(i-1\) 的“源”,右子树放深度为 \(i-2\) 的“源”,此时最浅“源”的深度为 \(\lceil\frac{i+1}2\rceil\)。
对于 \(n\),找到最大的 \(i\) 满足 \(f_i\le n\),答案即位 \(i-\lceil\frac{i+1}2\rceil\)。
但是这样只能拿 \(90\) 分,因为当 \(n=6\) 时,这个算法会算出 \(1\),但是答案为 \(0\)。特判掉就能 \(AC\) 了。
代码
由于这个题目非常恶心,需要把询问离线下来,用滚动的方式递推,不然会 \(MLE\),还需要压位高精度,不然会 \(TLE\)。
/*
Luogu P4583 [FJOI2015] 世界树
2026-04-14
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{template<typename T>inline void read(T&x){x=0;char c=getchar();bool f=0;while(!isdigit(c)) c=='-'?f=1:0,c=getchar();while(isdigit(c)) x=x*10+c-'0',c=getchar();f?x=-x:0;}template<typename T>inline void write(T x){if(x==0){putchar('0');return ;}x<0?x=-x,putchar('-'):0;short st[50],top=0;while(x) st[++top]=x%10,x/=10;while(top) putchar(st[top--]+'0');}inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}inline void write(char c){putchar(c);}inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
struct Int{vector<int>a;friend void write(Int x){if(x.a.size()==0){write(0);return ;}for(int i=x.a.size()-1;i>=0;i--) write(x.a[i]);}friend void read(Int&x){x.a.clear();string s;read(s);int be=0;while(be<s.size()&&s[be]=='0') be++;if(be==s.size()){x.a.push_back(0);return;}s=s.substr(be);int len=s.size();for(int i=len;i>0;i-=8){int ls=0;for(int j=max(0,i-8);j<i;j++) ls=ls*10+(s[j]-'0');x.a.push_back(ls);}}Int(int x){while(x) a.push_back(x%100000000),x/=100000000;}Int(){a.clear();}void clear(){a.clear();}Int operator+(const Int&x)const{vector<int>b=x.a,a=this->a;int n=max(b.size(),a.size());b.resize(n+1),a.resize(n+1);for(int i=0;i<n;i++) a[i]+=b[i];for(int i=0;i<n;i++) a[i+1]+=a[i]/100000000,a[i]%=100000000;while(!a.empty()&&!a.back()) a.pop_back();Int A;A.a.swap(a);return{A};}bool operator<=(const Int&x)const{if(a.size()<x.a.size()) return 1;if(a.size()>x.a.size()) return 0;for(int i=a.size()-1;i>=0;i--) if(a[i]<x.a[i]) return 1;else if(a[i]>x.a[i]) return 0;return 1;}
};
Int n,a,b;
int cnt,ans[100];
struct que{Int n;int id;bool operator<(const que&t){return n<=t.n;}
}q[100];
void solve(){read(n);cnt++;q[cnt]={n,cnt};
}
signed main(){int T;read(T);for(int i=1;i<=T;i++) solve();sort(q+1,q+1+T);a=1,b=2;int w=1;for(int i=1;;i++){while(q[w].n<=b){ans[q[w].id]=i-ceil((i+1)/2.0);w++;if(w>T) break;}if(w>T) break;a=a+b;swap(a,b);b=b+1;}for(int i=1;i<=T;i++) if(q[i].n<=6&&(Int)6<=q[i].n) ans[q[i].id]=0;for(int i=1;i<=T;i++) write(ans[i]),write("\n");return 0;
}
