CF512D Fox And Travelling

Link
首先我们进行拓扑排序,最后留下的点就是不能到达的点。
那么把这些点去掉之后,剩下的就是一个森林,而树有两类:
(1.)无根树:可以任意选择一个叶节点开始,然后可以在任意一个节点结束。
(2.)有根树:根节点与某个不能到达的点相邻,那么如果要到达根节点就必须在最后到达。
对于有根树,设(f_{i,j})表示在(i)的子树中选(j)个的方案数,合并是卷积的形式,为了表示顺序要乘上组合数。
对于无根树,枚举强制哪个节点最后到达,然后就变成了有根树的情况。注意对于(n)个点选(m)的方案数((n e m)),一种情况会被计算(n-m)次,除掉即可。
时间复杂度为(O(n^3))

#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
const int N=107,P=1000000009;
int n,inv[N],C[N][N],deg[N],vis[N],fa[N],size[N],f[N][N],s[N],ans[N];std::vector<int>e[N],g[N];std::queue<int>q;
int read(){int x;scanf("%d",&x);return x;}
void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
int mul(int a,int b){return 1ll*a*b%P;}
void dp(int u,int fa)
{
    size[u]=0,f[u][0]=1,memset(f[u]+1,0,n<<2);
    for(int v:g[u])
    {
	if(v==fa) continue;
	dp(v,u),size[u]+=size[v];
	for(int i=size[u];~i;--i) for(int j=1;j<=size[v]&&j<=i;++j) inc(f[u][i],mul(C[i][j],mul(f[u][i-j],f[v][j])));
    }
    ++size[u],f[u][size[u]]=f[u][size[u]-1];
}
void dfs(int u,int fa)
{
    for(int v:g[u]) if(v^fa) dfs(v,u);
    dp(u,0);
    for(int i=0;i<=n;++i) inc(s[i],f[u][i]);
}
int main()
{
    n=read(),ans[0]=inv[0]=inv[1]=1;
    for(int i=2;i<=n;++i) inv[i]=mul(P-P/i,inv[P%i]);
    for(int i=0;i<=n;++i) for(int j=C[i][0]=1;j<=i;++j) inc(C[i][j]=C[i-1][j],C[i-1][j-1]);
    for(int m=read(),u,v;m;--m) ++deg[u=read()],++deg[v=read()],e[u].push_back(v),e[v].push_back(u);
    for(int i=1;i<=n;++i) if(std::sort(e[i].begin(),e[i].end()),deg[i]<2) q.push(i);
    for(int u;!q.empty();)
    {
	vis[u=q.front()]=1,q.pop();
	for(int v:e[u])
	    if(!vis[v])
	    {
		fa[u]=v,g[u].push_back(v),g[v].push_back(u);
		if(--deg[v]==1) q.push(v); 
		break;
	    }
    }
    for(int i=1;i<=n;++i)
	if(vis[i])
	{
	    if(!fa[i])
	    {
		memset(s,0,(n+1)<<2),dfs(i,0);
		for(int j=0;j<=size[i];++j) s[j]=mul(inv[size[i]-j],s[j]);
		for(int j=n;j;--j) for(int k=0;k<j;++k) inc(ans[j],mul(C[j][k],mul(s[j-k],ans[k])));
	    }
	    else if(!vis[fa[i]])
	    {
		g[i].erase(find(g[i].begin(),g[i].end(),fa[i])),dp(i,0);
		for(int j=n;j;--j) for(int k=0;k<j;++k) inc(ans[j],mul(C[j][k],mul(f[i][j-k],ans[k])));
	    }
	}
    for(int i=0;i<=n;++i) printf("%d
",ans[i]);
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12638003.html