P4583 [FJOI2015] 世界树
题意
要求构建一个 \(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;
}

浙公网安备 33010602011771号