题解:CF2162G Beautiful Tree

· · 题解

简要说明题意:

给出 n,构造一棵含 n 个节点的树。一条边 (u,v) 的权为 uv,要求树的边权之和是一个完全平方数。

题目分析:

想构造的方便一点,那我们构造的值最好是一个和 n 有关的东西。由于 1+3+5+\dots+(2n-1)=n^2,所以想到把奇数和偶数分成两堆,大于 2 的偶数和 1 连接,大于 1 的奇数和 2 连接。

至于为什么不是奇数和 1,偶数和 2,我一开始也是这么构造的,式子会麻烦一些。 :(

##### 偶数 记 $n=2k$,这个森林的和是 $3k^2+k-4$。 那我们连接 $(k-1,k)$(还可以把两棵树连起来),配凑一个 $k*(k-1)$,得到 $4k^2-4$,再将 $(1,4)$ 改为 $(2,4)$,得到了一个和为 $4k^2=n^2$ 的构造。 ##### 奇数 记 $n=2k-1$,和为 $3k^2-k-4$。 连接 $(k,k+1)$ 得到 $4k^2-4$,同理将 $(1,4)$ 改为 $(2,4)$,得到一个和为 $4k^2=(n+1)^2$ 的构造。 然后注意一下 `corner case`。 ##### 偶数 $n=2$ 应该是 `-1`。 $k=2,3$,即 $n=4,6$ 时,$(k-1,k)$ 会和 $(2,3)$ 重复。 $k=4,5$,即 $n=8,10$ 时,$(k-1,k),(2,4),(2,k)/(2,k-1)$ 会成环。 ##### 奇数 同理,需要单独构造一下 $n=3,5,7$。 梳理后感觉构造过程并不复杂,可是半夜做题让我多花了很多时间计算和查错。:( 代码如下: ```cpp #include<iostream> #include<algorithm> using namespace std; int main(){ int T,n; ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr); cin>>T; while(T--){ cin>>n; if(n==2){ cout<<"-1\n"; continue; } if(n==6){ cout<<"1 2\n"; cout<<"1 3\n"; cout<<"1 5\n"; cout<<"1 6\n"; cout<<"4 5\n"; continue; } if(n==8){ cout<<"1 2\n"; cout<<"1 3\n"; cout<<"1 4\n"; cout<<"1 5\n"; cout<<"1 6\n"; cout<<"1 8\n"; cout<<"3 7\n"; continue; } if(n==10){ cout<<"1 2\n"; cout<<"1 3\n"; cout<<"1 4\n"; cout<<"1 5\n"; cout<<"1 6\n"; cout<<"1 7\n"; cout<<"1 8\n"; cout<<"1 9\n"; cout<<"2 10\n"; continue; } if(!(n&1)){ cout<<(n>>1)-1<<' '<<(n>>1)<<'\n'; cout<<"2 4\n"; for(int i=6;i<=n;i+=2) cout<<"1 "<<i<<'\n'; for(int i=3;i<=n;i+=2) cout<<"2 "<<i<<'\n'; continue; } if(n==3){ cout<<"1 3\n"; cout<<"2 3\n"; continue; } if(n==5){ cout<<"1 3\n"; cout<<"2 3\n"; cout<<"3 4\n"; cout<<"3 5\n"; continue; } if(n==7){ cout<<"1 2\n"; cout<<"1 4\n"; cout<<"1 5\n"; cout<<"1 6\n"; cout<<"1 7\n"; cout<<"3 4\n"; continue; } if(n&1){ cout<<((n+1)>>1)<<' '<<((n+1)>>1)+1<<'\n'; cout<<"2 4\n"; for(int i=6;i<=n;i+=2) cout<<"1 "<<i<<'\n'; for(int i=3;i<=n;i+=2) cout<<"2 "<<i<<'\n'; continue; } } return 0; } ```