Codeforces F. Cowmpany Cowmpensation

Description

有一棵树,现在要给每个节点赋一个在1到D之间的权值,问有多少种方案满足任意一个节点的权值都不大于其父亲的权值。
n<=3000,D<=1e9
题面

Solution

容易发现 \(f(D)\) 是一个 \(n\) 次多项式.
求出 \(f(1),f(2),...,f(n+1)\) 之后拉格朗日插值即可.

#include<bits/stdc++.h>
using namespace std;
const int N=3010,mod=1e9+7;
int n,m,head[N],to[N*2],nxt[N*2],fa[N],num=0,f[N][N],inv[N];
inline void link(int x,int y){nxt[++num]=head[x];to[num]=y;head[x]=num;}
inline void dfs(int x){
    for(int i=1;i<=n+1;i++)f[x][i]=1;
    for(int i=head[x],u;i;i=nxt[i]){
        if((u=to[i])==fa[x])continue;
        dfs(u);
        int sum=0;
        for(int j=1;j<=n+1;j++){
            sum=(sum+f[u][j])%mod;
            f[x][j]=1ll*f[x][j]*sum%mod;
        }
    }
}
int main(){
  freopen("pp.in","r",stdin);
  freopen("pp.out","w",stdout);
  cin>>n>>m;
  for(int i=2;i<=n;i++)cin>>fa[i],link(fa[i],i);
  dfs(1);
  for(int i=2;i<=n+1;i++)f[1][i]=(f[1][i]+f[1][i-1])%mod;
  if(m<=n+1)cout<<f[1][m],exit(0);
  inv[0]=inv[1]=1;
  for(int i=2;i<=n;i++)inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
  int ans=0;
  for(int i=1;i<=n+1;i++){
      int t=1;
      for(int j=1;j<=n+1;j++){
          if(i==j)continue;
          t=1ll*t*(m-j)%mod*(i>=j?inv[i-j]:-inv[j-i])%mod;
      }
      ans=(ans+1ll*t*f[1][i])%mod;
  }
  cout<<(ans+mod)%mod;
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Yuzao/p/9270626.html