[hiho1952]运算数

可以发现如果将根的结果写成多项式,可以发现只需要预处理出f[i][j]表示以i为根的子树j次项有多少个,g[i]表示从n个数中选取i个数相乘的和,就可以通过\sum_{i=1}^{n}f[1][i]\cdot g[i]\cdot (n-i)!$计算。可以发现有递推式:$g[i]=g[i-1]\cdot i\cdot \sum_{i=1}^{n}a[j]$,当符号是+,f[i][j]=f[ls][j]+f[rs[j]];当符号是*,$f[i][j]=\sum\limits_{k=1}^{j-1}f[ls][k]\cdot f[rs][j-k]$;当是叶子节点,f[i][j]=[j==1]。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define mod 1000000007
 4 #define N 6005
 5 long long n,p,ans,jc[N],a[N],x[N],y[N],sz[N],dp[N][N],f[N];
 6 char s[N][11];
 7 void dfs(int k){
 8     if (!x[k]){
 9         sz[k]=dp[k][1]=1;
10         return;
11     }
12     dfs(x[k]);
13     dfs(y[k]);
14     sz[k]=sz[x[k]]+sz[y[k]];
15     if (s[k][0]=='+')
16         for(int i=1;i<=sz[k];i++)dp[k][i]=(dp[x[k]][i]+dp[y[k]][i])%mod;
17     else
18         for(int i=1;i<=sz[x[k]];i++)
19             for(int j=1;j<=sz[y[k]];j++)dp[k][i+j]=(dp[k][i+j]+dp[x[k]][i]*dp[y[k]][j])%mod;
20 }
21 int main(){
22     scanf("%lld",&n);
23     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
24     f[0]=1;
25     for(int i=1;i<=n;i++)
26         for(int j=i;j>=0;j--)f[j]=(f[j]+j*f[j-1]%mod*a[i])%mod;
27     for(int i=1;i<=2*n-1;i++){
28         scanf("%lld",&p);
29         if (p==1)scanf("%lld%lld%s",&x[i],&y[i],s[i]);
30     }
31     jc[1]=1;
32     for(int i=2;i<=n;i++)jc[i]=jc[i-1]*i%mod;
33     dfs(1);
34     for(int i=1;i<=n;i++)ans=(ans+jc[n-i]*dp[1][i]%mod*f[i])%mod;
35     printf("%lld",ans);
36 }
View Code

 

posted @ 2019-07-28 10:28  PYWBKTDA  阅读(129)  评论(0编辑  收藏  举报