题解【UR #20】跳蚤电话
首先转化题意,变成有多少种删除点的顺序能够将所有点删完。
于是我们可以做树形dp,设 fi 表示 i 的子树内删完的排列数。
但是这样因为排列的原因,两个子树之间不独立,不好转移。
这个时候我们可以算随机排列能删完的概率,最后乘上 (n−1)! 就是答案(因为 1 不能删除)。
于是设 fi 表示 i 的子树按随机顺序删点,能删完的概率。
答案显然是 ∏u∈son(1)fu×(n−1)!
考虑转移,对于 i 的子树,我们钦定他最后一个被删除的点,设这个点为 j。
若 j=i,则贡献显然是 ∏u∈son(i)fu ,因为只要是 i 在最后一个的合法排列都可以。
若 j≠i,假设 i 到 j 路径上的点为 a1,a2,…,ak,那么删除每个 al时,他的除了 al+1 的所有子树都应该已经删除完,所以贡献是∏kl=11sizal−sizal+1∏u∈son(al),u≠al+1fu。
当然两种情况都要乘一个 1sizi
这样做的复杂度是 O(n2),不能通过。
考虑优化,我们注意到如果我们钦定的点是 i 的儿子 u 子树中一点 j,那么 j 对 i 的贡献只是对 u 的贡献前边加上一个 i。
于是我们设 gi=fi×sizi,有 gi=∏u∈son(i)fi+∑u∈son(i)gu1sizi−sizu∏v∈son(i),u≠vfv,fi=gi×1sizi
每次算出所有儿子的 f 的乘积,然后撤销每个儿子的贡献算答案即可,这样复杂度是 O(nlogn),因为还要求逆元。
当然也可以维护一个前缀后缀拼起来,复杂度 O(n),只不过我没写。
Code
#include<bits/stdc++.h>
#define N 2001001
#define MAX 2001
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=998244353,inf=1e18,inv2=(mod+1)/2;
inline void read(ll &ret)
{
ret=0;char c=getchar();bool pd=false;
while(!isdigit(c)){pd|=c=='-';c=getchar();}
while(isdigit(c)){ret=(ret<<1)+(ret<<3)+(c&15);c=getchar();}
ret=pd?-ret:ret;
return;
}
ll n,x,y;
ll f[N],g[N];
ll siz[N];
vector<ll>v[N];
inline ll qpow(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
ret*=a,ret%=mod;
b>>=1;
a*=a;
a%=mod;
}
return ret;
}
inline void dfs(ll ver,ll fa)
{
siz[ver]=1;
g[ver]=1;
ll res=1;
for(int i=0;i<v[ver].size();i++)
{
ll to=v[ver][i];
if(to==fa)
continue;
dfs(to,ver);
siz[ver]+=siz[to];
g[ver]*=f[to];
g[ver]%=mod;
res*=f[to];
res%=mod;
}
for(int i=0;i<v[ver].size();i++)
{
ll to=v[ver][i];
if(to==fa)
continue;
g[ver]+=g[to]*res%mod*qpow(f[to],mod-2)%mod*qpow(siz[ver]-siz[to],mod-2)%mod;
if(g[ver]>=mod)
g[ver]-=mod;
}
f[ver]=g[ver]*qpow(siz[ver],mod-2)%mod;
return;
}
signed main()
{
read(n);
for(int i=1;i<n;i++)
{
read(x);
read(y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs(1,0);
ll ans=1;
for(int i=0;i<v[1].size();i++)
ans*=f[v[1][i]],ans%=mod;
ll tmp=1;
for(int i=2;i<n;i++)
tmp*=i,tmp%=mod;
printf("%lld\n",ans*tmp%mod);
exit(0);
}
标签:
动态规划
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!