P7393 「TOCO Round 1」Eternal Star 题解
神仙题。
\large{\text{Solution}}
考虑构造一棵在根节点处取得最大点权
需要限制如下:
-
子节点的点权,肯定包含了
1\cdots k-1 。若子节点中没有权值为
p 的,那么让根节点变为p 则可使得整棵树的最大值变成k-1 且不会产生矛盾,与我们的期望不符。 -
每种权值对应的子节点有多个。
若没有这层限制,我们当然可以没有顾虑的使得根节点变为
p ,而原本权值为p 的子节点变为p+1 ,根节点因此变小了(称这一些列操作为 C,下面将会用到)。但是题目中有着 "点权和最小" 这一要求,于是我们可以通过调整各种子节点的数量来规避这种情况。具体的,我们设点权为
p 的子节点的个数为x ,那么为了保持根节点大小不变,应该有k+px<p+(p+1)x ,化简得到x>k-p 。综上,第
p 种子节点至少要有k-p+1 个。为了使点数最少,我们取等。
通过以上方式建立子节点,即可确定一个值为
该方法实际得分 55pts,错误的原因是建树所使用的节点过多。
优化
为了通过此题,我们需要让所用的总结点数更小,也就需要优化以上建树过程。
观察上述思路,貌似无懈可击,但是我们应该注意到特殊的第
也就是说,对调
具体的,如果使用这个优化,我们要在原本的
将上述优化具象化,我们建树的方式变为:建立两棵对称的树,将其根连接,使得其左右两个根下的
至此,本题结束。
\large{\text{Code}}
实现上有一个细节,就是在递归处理子树的时候不能再使用上文的优化。因为用了优化后建的树的对称性,其最大值可以在两个根的位置变化(我们最终答案不关心最大值的位置所以可以使用,但是递归到子树的时候我们有必要做这个限制),这就会导致我们对祖先的限制都失效。因此优化只能在最开始使用。
#include <bits/stdc++.h>
using namespace std;
int K,x,n=0,tot;
pair<int,int> ans[1000010];
int solve(int k,int op){
int u=++n;
if(k==1) return u;
if(u==1) ans[++tot]=make_pair(u,solve(k-1,1));
for(int i=1;i<k-(u==1);i++){
for(int j=1;j<=k-i+1+op;j++){
ans[++tot]=make_pair(u,solve(i,0));
}
}
return u;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>K>>x;
solve(K,0);
cout<<n<<'\n';
for(int i=1;i<=tot;i++)
cout<<ans[i].first<<' '<<ans[i].second<<'\n';
return 0;
}