WC2019 数树

Task 0

判断有多少条相同边即可。

复杂度\(O(N)\)

namespace Subtask1{
	pair<int,int> e1[N],e2[N];
	void Main(int n,int y){
		for(int i=1,u,v;i<n;i++){
			scanf("%d%d",&u,&v);
			e1[i] = pair<int,int> (min(u,v), max(u,v));
		}
		for(int i=1,u,v;i<n;i++){
			scanf("%d%d",&u,&v);
			e2[i] = pair<int,int> (min(u,v), max(u,v));
		}
		sort(e1+1,e1+n),sort(e2+1,e2+n);
		int j = 1,B = n;
		for(int i=1;i<n;i++){
			while(j<n&&e2[j]<e1[i])++j;
			if(j<n && e2[j] == e1[i]) B--;
		}
		cout << qpow(y,B) << endl;
	}
}

Task 1

考虑prufer序列,如果硬点了一些边一定被重复覆盖,那么硬点这\(c\)个联通块的方案是:

\[n^{c-2} \prod siz_i \]

考虑系数,硬点了\(a\)条边会在硬点\(b\)条边中出现了\(\binom{a}{b}\)次,恰好\(a\)条边的贡献是\(y^{n-a}\)

考虑:

\[\sum _i\binom {A}{i} x^i = (x+1)^A \]

那么系数设置为\(y^{-1}-1\)时,正好会贡献\(y^{-A}\)

\(siz\)的贡献拆组合意义,即:每个连通块内都要选一个节点作为代表。

\(f[x][0/1]\)表示当前节点所在连通块是否选了代表。

复杂度$O(n) $

namespace Subtask2{
	int hed[N],to[N<<1],nxt[N<<1],cnt;
	inline void adde(int u,int v){++cnt;to[cnt]=v,nxt[cnt]=hed[u];hed[u]=cnt;}
	int f[N][2],Val;
	inline void dfs(int x,int pre){
		f[x][1] = n, f[x][0] = 1;
		for(int i=hed[x];i;i=nxt[i]){
			int v=to[i];if(v==pre)continue;
			dfs(v,x);int f1=0,f0=0;
			f1 = add(mul(f[x][1], add(mul(Val,f[v][0]),f[v][1])), mul(mul(Val, f[x][0]), f[v][1]));
			f0 = mul(f[x][0], add(mul(Val, f[v][0]),f[v][1]));
			f[x][1] = f1, f[x][0] = f0;
		}
	}

	void Main(int n,int y){
		for(int i=1,u,v;i<n;i++){
			scanf("%d%d",&u,&v);
			adde(u,v),adde(v,u);
		}Val = sub(qpow(y,mod-2),1);
		dfs(1,0);
		// cout << mul(f[1][1], qpow(9,mod-2)) << endl;
		printf("%d\n",mul(qpow(1ll*n*n%mod,mod-2),mul(qpow(y,n), f[1][1])));
	}
}

Task 2

容斥系数和以上一样,\(f[i]\)表示\(i\)个点的连通块的贡献。现在要枚举的树是两颗树,所以方案的贡献要平方。

写成\(EGF\)之后\(exp\)就行了。

\(O(n\log n)\)

namespace Subtask3{
	using namespace Template_Poly;
	Poly f;
	int ifac[N], fac[N], Val;
	inline void init(int n = 1e5){
		fac[0] = ifac[0] = 1;for(int i=1;i<=n;i++)fac[i] = mul(fac[i-1], i);
		ifac[n] = qpow(fac[n], mod-2);for(int i=n-1;i;i--)ifac[i] = mul(ifac[i+1], i+1);
	}
	inline void initf(int n){
		f.resize(n+1);
		for(int i=1,w = 1;i<=n;i++, w = mul(w, Val)){
			f[i] = w;f[i] = mul(f[i], mul(qpow(i,max(0,i-2)), 1ll*n*n%mod));
			f[i] = mul(f[i], 1ll*i*i%mod);
			f[i] = mul(f[i], ifac[i]);
		}
	}
	void Main(int n,int y){
		Val = sub(qpow(y,mod-2),1);
		init();initf(n);
		f = exp(f);
		int ans = mul(f[n],fac[n]);
		ans = mul(ans, qpow(1ll*n*n%mod*n%mod*n%mod,mod-2));
		ans = mul(ans, qpow(y,n));
		cout << ans << endl;
	}
}
posted @ 2019-09-27 15:58  jerome_wei  阅读(210)  评论(0编辑  收藏  举报