LGP3240题解

该死的破题意

题意:给出一车不等式,问有多少种不同的可能的包含 \(n-1\)\(<,=\) 和长度为 \(n\) 的排列,将符号插入排列后不会与给定的不等式冲突。

定义两个包含不等号和排列的“序列”相同的条件为不等号和排列能够推出的不等式相同。

首先给出的不等式中等号屁用没有,用并查集缩在一起。

容易发现剩下的部分是一车有根树。先建立超级源点链接所有有根树的根方便统计。

设这棵树的深度为 \(k\) ,那么此题等价将这棵树划分成 \(k\) 个部分,每个部分非空,且父子不能在同一个部分中。

\(dp[u][k]\) 表示 \(u\) 为根的子树划分成了 \(k\) 个部分。

合并的时候是一个背包:

\[ans[i+j-k]=\sum_{i=0}^{n}\sum_{j=0}^{m}\sum_{k=0}^{\min(i,j)}f[i]\times\times g[j]\times\binom{(i-1)+j-k}{(i-1)-k,j-k,k} \]

\((i-1)\) 是因为有一个根节点要单独算。

直接暴力转移的复杂度是 \(O(n^3)\) 的。

#include<cstdio>
#include<cctype>
const int M=105,mod=1e9+7;
int n,m,E,tot,cnt,h[M],sz[M],id[M],C[M][M],dp[M][M];int u[M],v[M];
struct Edge{
	int v,nx;
}e[M<<1];
inline void Add(const int&u,const int&v){
	e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
}
struct DSU{
	int f[M];
	inline void init(const int&n){
		for(int i=1;i<=n;++i)f[i]=i;
	}
	inline int Find(const int&u){
		return f[u]==u?u:f[u]=Find(f[u]);
	}
	inline bool Merge(int u,int v){
		if((u=Find(u))^(v=Find(v)))return f[u]=v,true;return false;
	}
}dsu;
inline int min(const int&a,const int&b){
	return a>b?b:a;
}
inline void DFS(const int&u){
	dp[u][sz[u]=1]=1;
	for(int v,E=h[u];E;E=e[E].nx){
		DFS(v=e[E].v);static int T[M];
		for(int i=1;i<=sz[u];++i)for(int j=1;j<=sz[v];++j)for(int k=0;k<=i&&k<=j;++k){
			T[i+j-k]=(T[i+j-k]+(1ll*dp[u][i]*dp[v][j]%mod)*(1ll*C[(i-1)+j-k][(i-1)-k]*C[j][k]%mod))%mod;
		}
		sz[u]+=sz[v];for(int i=1;i<=sz[u];++i)dp[u][i]=T[i],T[i]=0;
	}
}
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
inline char read_typ(){
	char s;while(s=getchar(),s!='<'&&s!='=');return s=='<';
}
signed main(){
	int x,y,sz,ans(0);bool typ;C[0][0]=1;
	scanf("%d%d",&n,&m);dsu.init(n);sz=n;
	for(int i=1;i<=n;++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;
	}
	for(int i=1;i<n;++i){
		x=read();typ=read_typ();y=read();if(!typ)sz-=dsu.Merge(x,y);else++E,u[E]=x,v[E]=y;
	}
	for(int u=1;u<=n;++u)if(dsu.Find(u)==u)id[u]=++tot;
	for(int i=1;i<=E;++i)u[i]=id[dsu.Find(u[i])],v[i]=id[dsu.Find(v[i])];dsu.init(tot);
	for(int i=1;i<=E;++i)if(!dsu.Merge(u[i],v[i]))return printf("0"),0;dsu.init(tot);
	for(int i=1;i<=E;++i)Add(u[i],v[i]),dsu.Merge(v[i],u[i]);for(int u=1;u<=tot;++u)if(u==dsu.Find(u))Add(0,u);
	n=tot+1;DFS(0);for(int i=0;i<=n;++i)ans=(ans+dp[0][i])%mod;printf("%d",ans);
}
posted @ 2022-04-24 08:53  Prean  阅读(23)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};