专栏文章
题解:P14260 期待(counting)
P14260题解参与者 10已保存评论 9
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 9 条
- 当前快照
- 1 份
- 快照标识符
- @minrsgnx
- 此快照首次捕获于
- 2025/12/02 07:18 3 个月前
- 此快照最后确认于
- 2025/12/02 07:18 3 个月前
tag:树形结构,计数。
以下为了表述方便,称期待的方案为合法。
暴力
直接枚举所有合法移动方案,复杂度 ,期望得分 。
特殊性质 B
菊花图部分分。
事实上发现在菊花图上只有四种本质不同的情况,直接求出对应答案公式即可。
若 ,则有两种情况:
- 其一为根,如样例 1 的第一组数据,距离为 时要走一条经过该两点的路径,共 种。距离为 时或者不动,或者经过 之间的边和另一条边,或者在 之间的边上两端点互换,共 种,最终答案为 。
- 为两不同叶子,同样例第二组数据,答案为 。
复杂度 ,期望得分 。
特殊性质 C
链部分分。不妨设 与 连边,我们可以自然地定义从小到大和从大到小两种移动方向。
首先考虑合法移动方案的条件。样例非常良心地给我们提示了一种小 corner case:在一条边上两端点互换。容易发现只有这一种情况可以使得两棋子移动方向不同。以下不再赘述。
发现其余情况下只要两棋子移动方向相同则方案合法。再根据非常良心的样例解释容易发现除了 不动外的所有方案都可以两两配对,每对恰互为调换移动方向后的结果。因此我们只考虑从小到大的情况。
如上我们将问题转化为:求区间组 的数量,使得 ,且 。
直接枚举 可以 求出方案数,期望得分 。
考虑 ,显然 。若 ,则要求 ,有 种可能。同理 有 种可能。其中有一种重复方案:。
不妨设 ,由上可知 时有 种方案,即求 ,容易后缀和优化 求出。期望得分 。
特殊性质 A
完全二叉树的大部分性质我不知道怎么用。这个部分分是正解的一部分。
容易证明合法移动方案中经过的所有点一定在同一条链上。只要确定这条链就可以沿用链部分分的解法。
考虑以 为根时 的子树中点作为 ,以 为根时 的子树中点作为 ,类似地只需求 ,因为 和 都是 的,统计深度相同的点数后直接计算可以做到 。
正解
同完全二叉树部分分直接算可以做到 。同链部分分可以优化至 ,期望得分 。
Code:
CPPint n,y,s;
int d[100003];
vector<int>e[100003];
int c0[100003];
int c1[100003];
int dep[100003],dp0,dp1;
void dfs(int u,int fa){
for(int i=0,v;i<d[u];++i){
v=e[u][i];if(v==fa)continue;
dep[v]=dep[u]+1;dp0=max(dp0,dep[v]);
++c0[dep[v]];dfs(v,u);
}
}
int dis;
void dfs1(int u,int fa){
if(u==s){
dis=dep[u];
dep[u]=dp0=0;
c0[0]=1;dfs(u,fa);
return;
}for(int i=0,v;i<d[u];++i){
v=e[u][i];if(v==fa)continue;
dep[v]=dep[u]+1;dfs1(v,u);
}
}
ll ans;
inline void solve(){
cin>>n>>y>>s;ans=0;
for(int i=1;i<=n;++i){
d[i]=0;e[i].clear();
}for(int i=1,u,v;i<n;++i){
cin>>u>>v;++d[u],++d[v];
e[u].push_back(v);
e[v].push_back(u);
}dep[y]=0;dfs1(y,0);
for(int i=0;i<=dp0;++i)
c1[i]=c0[i],c0[i]=0;
dp1=dp0;swap(y,s);
dep[y]=0;dfs1(y,0);
for(int i=max(dp0,dp1);i>=0;--i)
ans+=((ll)c0[i]*c1[i+1]+(ll)c1[i]*c0[i+1]+(ll)c0[i]*c1[i])*(dis+i*2+1),\
c0[i]+=c0[i+1],c1[i]+=c1[i+1];
ans=ans*2-1;if(dis==1)ans+=2;
for(int i=0;i<=n;++i)c0[i]=c1[i]=0;
cout<<ans<<"\n";
}
相关推荐
评论
共 9 条评论,欢迎与作者交流。
正在加载评论...