ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF512D Fox And Travelling(DP 计数)

2022-08-14 16:33:06  阅读:160  来源: 互联网

标签:int CF512D ll Fox ret Maxn tot Travelling mod


CF512D Fox And Travelling

给定一张 \(n\) 个点 \(m\) 条边的无向图,每次选择一个叶子结点并将它和连接它的边删除。

对于每个 \(k\in[0,n]\),问有序选择 \(k\) 个点的方案数。

\(n\le 100\)。

显然如果有环,那么所有环上的点都无法被选择,可以选择的只是一棵棵树。

按照是否有环,可以将所有树分为两类,求出每一棵树的答案,再背包乘起来:

  • 一棵单独的树,可以被取完,从各个方向都可以选择,直接背包计算即可。
  • 树根连在“环”上,只可以从儿子向上取。
    • \(\color{yellow}{\bigstar\texttt{Trick}}\):按照上面的方法,将每个点当做根节点做一遍。设树的大小为 \(n\),发现每种选择 \(k\) 个点的情况都会在 \(n-k\) 个点中计算一遍,那么答案除 \(n-k\) 即可。

将长度为 \(l_1,l_2\) 的序列合并起来的方案数为 \(\binom{l_1+l_2}{l_1}\),那么直接用背包合并即可。

#define Maxn 105
#define Maxm 10005
#define mod 1000000009
int n,m,tot,cnt;
int C[Maxn][Maxn],ind[Maxn];
int hea[Maxn],nex[Maxm<<1],ver[Maxm<<1];
bool Covered[Maxn];
vector<int> g[Maxn];
inline void add(int x,int y){ ver[++tot]=y,nex[tot]=hea[x],hea[x]=tot; }
inline ll ksm(ll x,ll y=mod-2)
{
	ll ret=1;
	for(;y;y>>=1,x=x*x%mod) if(y&1) ret=ret*x%mod;
	return ret;
}
struct TREE
{
	int opt,rt,sall,siz[Maxn];
	ll dp[Maxn],tmp[Maxn][Maxn];
	void dfs(int x,int fa)
	{
		tmp[x][0]=1,siz[x]=0;
		for(int v:g[x]) if(v!=fa)
		{
			dfs(v,x);
			for(int su=siz[x];su>=0;su--) for(int sv=1;sv<=siz[v];sv++)
				(tmp[x][su+sv]+=tmp[x][su]*tmp[v][sv]%mod*C[su+sv][sv]%mod)%=mod;
			siz[x]+=siz[v];
		}
		(tmp[x][siz[x]+1]+=tmp[x][siz[x]])%=mod;
		siz[x]++;
	}
	inline void ADD(int x)
	{
		memset(tmp,0,sizeof(tmp)),dfs(x,0);
		for(int i=0;i<=sall;i++) (dp[i]+=tmp[x][i])%=mod;
	}
	void Find(int x,int fa) { ADD(x); for(int v:g[x]) if(v!=fa) Find(v,x); }
	void Count(int x,int fa) { sall++; for(int v:g[x]) if(v!=fa) Count(v,x); }
	void solve()
	{
		Count(rt,0);
		if(opt==0) { Find(rt,0); for(int i=0;i<sall;i++) dp[i]=dp[i]*ksm(sall-i)%mod; }
		else ADD(rt);
	}
}subtree[Maxn];
ll ans[Maxn];
int main()
{
	C[0][0]=1;
	for(int i=1;i<=100;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
	}
	n=rd(),m=rd();
	for(int i=1,u,v;i<=m;i++)
		u=rd(),v=rd(),add(u,v),add(v,u),ind[u]++,ind[v]++;
	queue<int> q;
	for(int i=1;i<=n;i++) if(ind[i]<=1) q.push(i);
	while(!q.empty())
	{
		int cur=q.front(); q.pop();
		bool exist=false;
		Covered[cur]=true;
		for(int i=hea[cur];i;i=nex[i])
		{
			if(Covered[ver[i]]) g[cur].pb(ver[i]),g[ver[i]].pb(cur);
			else
			{
				exist=true,ind[ver[i]]--;
				if(ind[ver[i]]==1) q.push(ver[i]);
			}
		}
		if(!exist) cnt++,subtree[cnt].opt=0,subtree[cnt].rt=cur;
	}
	for(int i=1;i<=n;i++) if(!Covered[i])
		for(int j=hea[i];j;j=nex[j]) if(Covered[ver[j]])
			cnt++,subtree[cnt].opt=1,subtree[cnt].rt=ver[j];
	for(int i=1;i<=cnt;i++) subtree[i].solve();
	ans[0]=1;
	for(int i=1,pre=0;i<=cnt;i++)
	{
		for(int su=pre;su>=0;su--) for(int sv=1;sv<=subtree[i].sall;sv++)
			(ans[su+sv]+=ans[su]*subtree[i].dp[sv]%mod*C[su+sv][su]%mod)%=mod;
		pre+=subtree[i].sall;
	}
	for(int i=0;i<=n;i++) printf("%lld\n",ans[i]);
	return 0;
}

标签:int,CF512D,ll,Fox,ret,Maxn,tot,Travelling,mod
来源: https://www.cnblogs.com/EricQian/p/16585661.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有