[CF995F]Cowmpany Cowmpensation

為{幸葍}努か 提交于 2021-02-15 06:04:00

codeforces

description

一棵$n$个节点的树,给每个节点标一个$[1,m]$之间的编号,要求儿子的权值不大于父亲权值。求方案数。$n\le3000,n\le10^9$

sol

可以证明答案是关于$m$的一个$n$次多项式。我不会证。 如果$P(x)$是关于$x$的$n$次多项式,则有 $$P(x)=\sum_{i=0}^{n}(-1)^{n-i}P(i)\frac{x(x-1)...(x-n)}{(n-i)!i!(x-i)}$$ 可见杜教$\mbox{PPT}$《多项式与求和》。 所以只要对$[1,n]$求答案就可以了,很显然是一个$O(n^2)$的$dp$,所以复杂度是$O(n^2)$。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 3005;
const int mod = 1e9+7;
int n,m,nxt[N],head[N],f[N][N],inv[N],ans;
void dfs(int u){
	for (int i=1;i<=n;++i) f[u][i]=1;
	for (int v=head[u];v;v=nxt[v]){
		dfs(v);
		for (int i=1;i<=n;++i)
			f[u][i]=1ll*f[u][i]*f[v][i]%mod;
	}
	for (int i=2;i<=n;++i) (f[u][i]+=f[u][i-1])%=mod;
}
int main(){
	n=gi();m=gi();inv[0]=inv[1]=1;
	for (int i=2;i<=n;++i) inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
	for (int i=2,ff;i<=n;++i)
		nxt[i]=head[ff=gi()],head[ff]=i;
	dfs(1);
	if (m<=n) return printf("%d\n",f[1][m]),0;
	for (int i=1;i<=n;++i){
		int sum=f[1][i];
		for (int j=0;j<=n;++j)
			if (j!=i) sum=1ll*sum*(m-j)%mod*(i>j?inv[i-j]:mod-inv[j-i])%mod;
		(ans+=sum)%=mod;
	}
	printf("%d\n",ans);return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!