题解 数叶子

传送门

考虑写个贡献形式:
枚举是哪个点是叶子,发现不可避免的需要枚举最终选定的区间

i=1m(mi+1)u=1ndegu×i×(mi)degu1_(mdegu)ndegu1_

然后变形

u=1ndegu×(mdegu)ndegu1_i=1m(mi+1)×i×(mi)degu1_

不同的 degu 肯定只有根号种,然后后面那个式子可以拉格朗日插值,注意因为是下降幂所以好多点值都是 0
然后题解给出了这样一个组合恒等式来优化后面的式子:

i=1m(mi+1)×i×(mi)degu1_=(m+2d+2)d!

发现实际上是枚举一个区间,在区间内选一个球,在区间外选 degu1 个球
将枚举区间的过程扔到组合数里
那么留出 2 个特殊位置给端点
m+2 个位置中选出 d+2 个,然后区间就是三个相邻的球
枚举这个区间在哪里就可以了
复杂度 O(n)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define fir first
#define sec second
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
pair<int, int> e[N];
const ll mod=1004535809;

namespace force{
	ll ans;
	bool vis[N];
	int id[N], rk[N], deg[N];
	void dfs(int u) {
		if (u>=n) {
			for (int l=1; l<=m; ++l) {
				int cnt=0;
				for (int i=1; i<=n; ++i) deg[i]=0;
				for (int r=l; r<=m; ++r) {
					if (vis[r]) {
						if (deg[e[rk[r]].fir]==0) ++cnt;
						if (deg[e[rk[r]].fir]==1) --cnt;
						++deg[e[rk[r]].fir];
						if (deg[e[rk[r]].sec]==0) ++cnt;
						if (deg[e[rk[r]].sec]==1) --cnt;
						++deg[e[rk[r]].sec];
					}
					ans=(ans+cnt)%mod;
				}
			}
			return ;
		}
		for (int i=1; i<=m; ++i) if (!vis[i]) {
			rk[id[u]=i]=u;
			vis[i]=1;
			dfs(u+1);
			vis[i]=0;
		}
	}
	void solve() {
		dfs(1);
		printf("%lld\n", ans);
	}
}

namespace task1{
	int deg[N];
	ll fac[N], inv[N], ans;
	inline ll C(int n, int k) {return fac[n]*inv[k]%mod*inv[n-k]%mod;}
	void solve() {
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<N; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<N; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		for (int i=1; i<n; ++i) ++deg[e[i].fir], ++deg[e[i].sec];
		for (int u=1; u<=n; ++u) {
			ll tem=0;
			for (int i=1; i<=m; ++i) if (m-i+1>=deg[u]) tem=(tem+i*fac[m-i+1]%mod*inv[m-i+1-deg[u]])%mod;
			if (m>=deg[u]) tem=C(m+2, deg[u]+2)*fac[deg[u]]%mod;
			if (m-deg[u]>=n-deg[u]-1) ans=(ans+tem*deg[u]%mod*fac[m-deg[u]]%mod*inv[m-deg[u]-(n-deg[u]-1)])%mod;
		}
		printf("%lld\n", ans);
	}
}

namespace task{
	int deg[N];
	map<int, ll> mp;
	ll fac[N], inv[N], ans;
	inline ll C(int n, int k) {return fac[n]*inv[k]%mod*inv[n-k]%mod;}
	ll calc(int d) {
		if (mp.find(d)!=mp.end()) return mp[d];
		if (m<d || m-d<n-d-1) return 0;
		ll tem=fac[d]*inv[d+2]%mod*d%mod;
		for (int i=m+2; i>m-d; --i) tem=tem*i%mod;
		for (int i=m-d; i>m-n+1; --i) tem=tem*i%mod;
		return mp[d]=tem;
	}
	void solve() {
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<N; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<N; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<N; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		for (int i=1; i<n; ++i) ++deg[e[i].fir], ++deg[e[i].sec];
		for (int u=1; u<=n; ++u) ans=(ans+calc(deg[u]))%mod;
		printf("%lld\n", ans);
	}
}

signed main()
{
	freopen("leaf.in", "r", stdin);
	freopen("leaf.out", "w", stdout);

	n=read(); m=read();
	if (m<n-1) {puts("0"); return 0;}
	for (int i=1; i<n; ++i) e[i].fir=read(), e[i].sec=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @   Administrator-09  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示