专栏文章
题解:P14254 分割(divide)
P14254题解参与者 5已保存评论 5
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @minkms4g
- 此快照首次捕获于
- 2025/12/02 03:57 3 个月前
- 此快照最后确认于
- 2025/12/02 03:57 3 个月前
首先发现如果 ,那么一定有 ,且 ,与题目要求矛盾。又由于 ,因此所有 均相等。
那么先固定 ,记 ,显然 即为 的子树中所有点的深度构成的集合,记 的子树中最大的深度为 ,则 。接下来要选出与 深度相同的 ,同样有 。剩下部分即为原树挖掉这 棵子树,设深度为 的点组成的集合为 ,则 。
此时 即表示 。也就是说, 且 ,其中至少有一个等号成立。
因此我们知道对于 ,至少要有 棵 的子树,同时至少要有另外一个 。直接枚举 和 ,设 且 的 有 个, 的点有 个,对这 个点中的每个 ,都能得到选出 且使得其中至少一个 的方案数为 ,其中 为排列数,。
还有一种情况:所有 均大于 ,而。这时一定有 ,对于 个 中的每一个都有 种方案。
直接 dfs 求出 和 数组后,预处理阶乘和阶乘逆元即可做到时间空间复杂度 。
upd:我的实现用到了排序,所以是 的。懒得想有没有严格 方法了。
Code:
CPPint n,k,m;
int fa[1000003];
int dep[1000003];
int mxd[1000003];
ll ans;
int c[1000003];
vector<int>d[1000003];
inline void solve(){
cin>>n>>k;dep[1]=0;
for(int i=2;i<=n;++i)
cin>>fa[i];
for(int i=2;i<=n;++i)
dep[i]=dep[fa[i]]+1,m=max(m,dep[i]);
for(int i=n;i>1;--i)
mxd[i]=max(mxd[i],dep[i]),\
mxd[fa[i]]=max(mxd[fa[i]],mxd[i]);
for(int i=1;i<=n;++i)
++c[dep[i]],d[dep[i]].push_back(mxd[i]);
for(int i=0;i<=m;++i)
sort(d[i].begin(),d[i].end());
for(int i=0,l,r;i<=m;++i){
for(l=r=c[i]-1;r>=0;r=l){
while(l>=0&&d[i][l]==d[i][r])--l;
if(l>=c[i]-1-k)continue;
if(r-l==1)continue;
ans=(ans+(A(c[i]-2-l,k-1)-A(c[i]-1-r,k-1)+ntf)*(r-l))%ntf;
if(c[i]-1-r==k-1)
ans=(ans+fac[k-1]*(r-l))%ntf;
}
}cout<<ans<<"\n";
}
相关推荐
评论
共 5 条评论,欢迎与作者交流。
正在加载评论...