题目大意:
一个树是 F I B FIB FIB树得是节点个数为斐波那契数,且(注意这个且)!!此外满足下面条件一个:
1.只有一个点
2.可以切一条边使得分出的两个子树都是
F
I
B
FIB
FIB树。
给你一棵树,问是否是
F
I
B
FIB
FIB树
注意这是个递归定义来着
解题思路:
- 首先我们知道 n = f i b [ i ] = f i b [ i − 1 ] + f i b [ i − 2 ] n=fib[i]=fib[i-1]+fib[i-2] n=fib[i]=fib[i−1]+fib[i−2]
- 那么 f i b [ i ] fib[i] fib[i]只能划分成 f i b [ i − 1 ] 和 f i b [ i − 2 ] fib[i-1]和fib[i-2] fib[i−1]和fib[i−2]
- 我们转化一下 f i b [ i ] = 2 ∗ f i b [ i − 2 ] + f i b [ i − 3 ] < 3 ∗ f i b [ i − 2 ] fib[i]=2*fib[i-2]+fib[i-3]<3*fib[i-2] fib[i]=2∗fib[i−2]+fib[i−3]<3∗fib[i−2]
- 那么我们知道一个树里面最多有两个子树的大小是 f i b [ i − 2 ] fib[i-2] fib[i−2]那么我们要选择切哪条边呢?
- 其实选择哪条边都一样因为, f i b [ i − 1 ] = f i b [ i − 2 ] + f i b [ i − 3 ] fib[i-1]=fib[i-2]+fib[i-3] fib[i−1]=fib[i−2]+fib[i−3]!!那么就是两条边最终还是会被切掉的,所以随便切一条就可以了
- 那么我们暴力去模拟题意就可以了?时间复杂度是
O
(
n
2
)
?
?
O(n^2)??
O(n2)??
很明显不是,因为每次分裂最大递归 l o g = 27 log=27 log=27层,斐波那契的层数!!
时间复杂度是 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))
AC code
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) {
read(first);
read(args...);
}
int n;
struct node {
int nxt, to;
}edge[maxn];
int head[maxn], cnt;
bool tag[maxn];
inline void add(int from, int to) {
edge[cnt] = {head[from],to};
head[from] = cnt++;
}
//........................
int f[maxn];
bool vis[maxn];
inline void init() {
ms(head,-1);
f[0] = f[1] = 1;
vis[1] = 1;
for(int i = 2; ; ++ i) {
f[i] = f[i-1] + f[i-2];
vis[f[i]] = 1;
if(f[i]>200000) break;
}
}
//........................
int siz[maxn];
int pos, posfa;
inline void dfs(int u, int fa,int num) {
siz[u] = 1;
for(int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].to;
if(v == fa || tag[i]) continue;
dfs(v,u,num);
if(~pos) return;
if(vis[siz[v]]&&vis[num-siz[v]]) {
tag[i] = tag[i^1] = 1;
pos = v;
posfa = u;
return;
}
siz[u] += siz[v];
}
}
inline void Div(int now, int num) {
if(num == 1) return;
pos = -1, posfa = -1;
dfs(now,0,num);
if(pos==-1) {
cout << "NO\n";
exit(0);
}
int backposfa = posfa, backupnum = num - siz[pos];
Div(pos,siz[pos]);
Div(backposfa,backupnum);
}
int main() {
IOS;
init();
cin >> n;
if(!vis[n]) {
cout << "NO";
return 0;
}
for(int i = 1; i <= n-1; ++ i) {
int u, v;
cin >> u >> v;
add(u,v);
add(v,u);
}
Div(1,n);
cout << "YES\n";
return 0;
}