题意:
给你n(n<=1e5)个节点。第i个节点的父亲是随机的,范围为0~i-1。
定义一棵树的值为 其中val[i]为以i为根的子树的所有点的权值之和。
给你a[i](i=1~n)(每个点的权值),求所有可能的树的平均值。
思路:找规律,看每个节点在n确定时被计算了多少次,发现
n=1 1
n=2 1 2
n=3 2 4 5
n=4 6 12 15 17
n=5 224 48 60 68 74
发现每一个n 的最后一项等于,sum[0]=1。(这里n从0开始)
然后每个n,第一项就是(n-1)!。即d[1]=(n-1)!
把差写出来,就很容易发现n确定时,d[i]=d[i-1]+c[n-1]/(i-1); 而d[n]就是
然后预处理d[n],阶乘,逆元就可以O(n)求答案了
代码:
#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=200010;
const ll mo=998244353;
ll n,m,k;
ll a[maxn],c[maxn],sum[maxn],d[maxn];
ll ans,ct,cnt,tmp,flag;
char s[maxn];
ll power(ll a,ll n) //aµÄn´Î·½mod
{
ll ans=1;
a=a%mo;
while (n)
{
if(n&1) ans=(ans*a)%mo;
n>>=1;
a=(a*a)%mo;
}
return ans;
}
int main()
{
c[0]=1;
for(int i=1;i<=100010;i++)
{
c[i]=(c[i-1]*(ll)i)%mo;
}
sum[0]=1;
for(int i=1;i<=100010;i++)
{
sum[i]=(sum[i-1]*(ll)i%mo+c[i-1])%mo;
//cout<<sum[i]<<endl;
}
int T,cas=1;
scanf("%d",&T);
while(T--)
{
ans=0; flag=1;
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
ll ans=0;
d[1]=c[n-1];
d[2]=d[1]*2;
d[n]=sum[n-1];
for(ll i=3;i<=n-1;i++)
{
d[i]=(d[i-1]+c[n-1]*power(i-1,mo-2)%mo)%mo;
//cout<<d[i]<<' * '<<endl;
}
//cout<<ans<<endl;
for(int i=1;i<=n;i++)
{
ans=(ans+a[i]*d[i]%mo)%mo;
}
ans=ans*power(c[n],mo-2)%mo;
printf("%lld\n",ans);
}
return 0;
}