[CF995F] Cowmpany Cowmpensation
\(\text{Problem}:\)Cowmpany Cowmpensation
\(\text{Solution}:\)
不难发现,虽然权值种类很多,但在一种分配方案中,不同的权值个数只有 \(O(n)\) 个。故设 \(f_{i}\) 表示分配了 \(i\) 种权值的方案数,答案为:
\[\sum\limits_{i=1}^{\min(n,D)}\binom{D}{i}f_{i}
\]
难以直接计算求得 \(f_{i}\),故考虑容斥求解。设 \(g_{i}\) 表示分配权值离散化后,最大权值为 \(i\) 的方案数。考虑在剩下的 \(i-1\) 种权值中选出 \(j-1\) 个,即\(f_{j}\) 在 \(g_{i}\) 中会出现 \(\binom{i-1}{j-1}\) 次,要减去 \(f_{j},j<i\) 对 \(f_{i}\) 的贡献。故有:
\[f_{i}=g_{i}-\sum\limits_{j=1}^{i-1}\binom{i-1}{j-1}f_{j}
\]
而 \(g_{i}\) 可以利用树形 \(dp\) 在 \(O(n^2)\) 的时间复杂度内求出。总时间复杂度 \(O(n^2)\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=3010, Mod=1e9+7;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,D,g[N][N],f[N];
int fac[N+5],inv[N+5];
inline int ksc(int x,int p) { int res=1; for(;p;p>>=1, x=1ll*x*x%Mod) if(p&1) res=1ll*res*x%Mod; return res; }
inline int C(int x,int y) { if(x<y||x<0||y<0) return 0; return 1ll*fac[x]*inv[x-y]%Mod*inv[y]%Mod; }
int head[N],maxE; struct Edge { int nxt,to; }e[N];
inline void Add(int u,int v) { e[++maxE].nxt=head[u]; head[u]=maxE; e[maxE].to=v; }
void DFS(int x)
{
for(ri int i=1;i<=n;i++) g[x][i]=1;
for(ri int i=head[x];i;i=e[i].nxt)
{
int v=e[i].to;
DFS(v);
for(ri int j=1;j<=n;j++) g[x][j]=1ll*g[x][j]*g[v][j]%Mod;
}
for(ri int i=1;i<=n;i++) g[x][i]=(g[x][i-1]+g[x][i])%Mod;
}
signed main()
{
fac[0]=1;
for(ri int i=1;i<=N;i++) fac[i]=1ll*fac[i-1]*i%Mod;
inv[N]=ksc(fac[N],Mod-2);
for(ri int i=N;i;i--) inv[i-1]=1ll*inv[i]*i%Mod;
n=read(), D=read();
for(ri int i=1;i<n;i++)
{
int x=read();
Add(x,i+1);
}
DFS(1);
for(ri int i=1;i<=n;i++)
{
f[i]=(g[1][i]-g[1][i-1]+Mod)%Mod;
for(ri int j=1;j<i;j++)
{
int w=1ll*C(i-1,j-1)*f[j]%Mod;
f[i]=(f[i]-w+Mod)%Mod;
}
}
int ans=0;
for(ri int i=1,now=D;i<=n&&i<=D;i++) ans=(ans+1ll*now*inv[i]%Mod*f[i]%Mod)%Mod, now=1ll*now*(D-i)%Mod;
printf("%d\n",ans);
return 0;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。