HDU 6267 Master of Random (找規律)
阿新 • • 發佈:2018-11-11
題意:
給你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; }