原题
题目描述
样例
输入
5 1000000007
2
3
4
5
107
输出
2
24
264
3240
736935633
思路
以下是乍一眼看不懂的官方题解:
这种规律过于玄学,所以我们找到了另一种解题思路:
因为要用到
序列,所以大家可以参考一下这篇博客。
- 因为n个点的无根树可以形成nn−2个不同的树,所以我们不妨设它的值为
,设n个点的森林个数为
。在第n个点加入时,我们可以选择
个点和它形成一棵树,那么就可以列出
式:
- 然后我们可以再定义一个n个点能形成的所有无根树的权值和为
,并枚举它的度数为
,列出
式:
2 (n-1-d) - 最后我们定义
为答案,列出
式:
*
我们只要根据以上公式打表即可,具体细节可以看看代码。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=5010;
ll t,n,mod,c[maxn][maxn],f[maxn],p[maxn],dp[maxn],ans[maxn];
int ksm(ll a,ll b)//这里要开long long,快速幂加快运算
{
if(b<=0)return 1;
ll k=1;
while(b)
{
if(b&1)k=k*a%mod;
b>>=1;a=(a*a)%mod;
}
return k;
}
int main()
{
scanf("%lld%lld",&t,&mod);c[0][0]=f[0]=f[1]=p[0]=p[1]=1;
for(int i=1;i<=5000;i++)
{
c[0][i]=1;
for(int j=1;j<=i;j++)c[j][i]=(c[j][i-1]+c[j-1][i-1])%mod;
}
for(int i=1;i<=5000;i++)
{
for(int j=1;j<i;j++)dp[i]=(j*j%mod*c[j-1][i-2]%mod*ksm(i-1,i-1-j)%mod+dp[i]%mod)%mod;
dp[i]=i*dp[i]%mod;
if(i^1)p[i]=ksm(i,i-2);
}
for(int i=2;i<=5000;i++)
for(int j=0;j<i;j++)
f[i]=(c[j][i-1]*f[i-j-1]%mod*p[j+1]%mod+f[i])%mod;
for(int i=2;i<=5000;i++)
for(int j=1;j<=i;j++)
ans[i]=(c[j-1][i-1]*((p[j]*ans[i-j]%mod+f[i-j]*dp[j]%mod)%mod)+ans[i]%mod)%mod;
while(t--)scanf("%lld",&n),printf("%lld\n",ans[n]);
return 0;
}