[CF995F] Cowmpany Cowmpensation(树形dp,拉格朗日插值)
樹形DP:
設f[u][i]f[u][i]f[u][i]表示給uuu的子樹分配工資,uuu點工資為iii的方案數
f[u][i]=∏v∈sonu(∑j=1if[v][j])f[u][i]=\prod\limits_{v\in son_u}(\sum\limits_{j=1}^{i}f[v][j])f[u][i]=v∈sonu?∏?(j=1∑i?f[v][j])
前綴和優化:
設g[u][i]=∑j=1if[u][j]g[u][i]=\sum\limits_{j=1}^{i}f[u][j]g[u][i]=j=1∑i?f[u][j]
f[u][i]=∏v∈sonug[v][i]f[u][i]=\prod\limits_{v\in son_u}g[v][i]f[u][i]=v∈sonu?∏?g[v][i]
時間復雜度O(nd)O(nd)O(nd)
考慮用拉格朗日插值優化成O(n2)O(n^2)O(n2):
設gu(x)g_u(x)gu?(x)為關于xxx的函數,代入xxx,即可得到g[u][x]g[u][x]g[u][x],
合理猜想gu(x)g_u(x)gu?(x)的次數為szusz_uszu?(uuu的子樹大小),可以用數學歸納法證明:
- 當 uuu 為葉子結點時,gu(x)=xg_u(x)=xgu?(x)=x,成立。
- 當 uuu 非葉子結點時,考慮:
gu(x)?gu(x?1)=∏v∈sonugv(x)g_u(x)-g_u(x-1)=\prod\limits_{v\in son_u}g_v(x)gu?(x)?gu?(x?1)=v∈sonu?∏?gv?(x)
由于 vvv 滿足猜想,即gv(x)g_v(x)gv?(x) 的次數為 szvsz_vszv?,則 gu(x)?gu(x?1)g_u(x)-g_u(x-1)gu?(x)?gu?(x?1) 的次數為 ∑v∈sonuszv\sum\limits_{v\in son_u}sz_vv∈sonu?∑?szv?,即 szu?1sz_u-1szu??1。
再還原差分,次數 +1,有 gu(x)g_u(x)gu?(x) 是關于 xxx 的 szu?1+1=szusz_u-1+1=sz_uszu??1+1=szu? 次函數。
所以我們只要知道g1(1),g1(2),...,g1(n)g_1(1),g_1(2),...,g_1(n)g1?(1),g1?(2),...,g1?(n),便可以用拉格朗日插值得出g1(d)g_1(d)g1?(d)
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int mod=1e9+7; const int N=3050; struct Edge{int v,nxt;}edge[N]; int n,cnt,head[N],fa[N]; int d,f[N][N],sum[N][N],inv[N],ans; int add(int a,int b){return a+b>=mod?a+b-mod:a+b;} int mul(int a,int b){return 1ll*a*b%mod;} void addedge(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt; } void dfs(int u){for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;dfs(v);for(int j=1;j<=min(n,d);j++)f[u][j]=mul(f[u][j],sum[v][j]);}for(int j=1;j<=min(n,d);j++) sum[u][j]=add(sum[u][j-1],f[u][j]); } int main(){scanf("%d%d",&n,&d);inv[1]=1;for(int i=2;i<=n;++i) inv[i]=mul(mod-mod/i,inv[mod%i]);for(int i=2;i<=n;i++){scanf("%d",&fa[i]);addedge(fa[i],i);}for(int i=1;i<=n;i++)for(int j=1;j<=min(n,d);j++) f[i][j]=1;dfs(1);if(d<=n) printf("%d\n",sum[1][d]);else{for(int i=1;i<=n;i++){int x=sum[1][i];for(int j=0;j<=n;++j) if(i^j) x=1ll*x*(d-j+mod)%mod*(i>j?inv[i-j]:mod-inv[j-i])%mod;ans=add(ans,x);}printf("%d\n",ans);}return 0; }總結
以上是生活随笔為你收集整理的[CF995F] Cowmpany Cowmpensation(树形dp,拉格朗日插值)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网络速度测试方法如何测试电脑速度
- 下一篇: 360路由器怎么设置设置步骤360路由器