AT4352-[ARC101C] Ribbons on Tree【dp,容斥】
正題
題目鏈接:
https://www.luogu.com.cn/problem/AT4352
https://atcoder.jp/contests/arc101/tasks/arc101_c
題目大意
nnn個點之間兩兩配對,要求配對點之間的路徑覆蓋整棵樹,求方案數
解題思路
考慮容斥,我們欽定有lll條邊沒有路徑覆蓋,就有dpdpdp狀態fi,j,lf_{i,j,l}fi,j,l?表示iii的子樹中,目前該子樹的聯通塊大小為jjj,已經切斷了lll條邊,我們發現該狀態已經是O(n3)O(n^3)O(n3)的,顯然無法通過。
考慮優化,每個dpdpdp狀態的容斥系數是(?1)l(-1)^l(?1)l,所以我們可以不用記錄lll這一維度,之間用狀態表示乘上了容斥系數的值。
那么我們就有dpdpdp方程,定義calc(x)calc(x)calc(x)表示xxx個點兩兩匹配的值
(?1)?fx,i?fy,j?calc(j)→fx,i(-1)*f_{x,i}*f_{y,j}*calc(j)\rightarrow f_{x,i}(?1)?fx,i??fy,j??calc(j)→fx,i?
fx,i?fy,j→fx,i+jf_{x,i}*f_{y,j}\rightarrow f_{x,i+j}fx,i??fy,j?→fx,i+j?
該方程的復雜度就是每個子樹的乘積,可以理解為每個點堆之間進行一次貢獻,時間復雜度O(n2)O(n^2)O(n2)
calc(x)=∏i=1x?1[i&1==1]icalc(x)=\prod_{i=1}^{x-1}[i\&1==1]icalc(x)=∏i=1x?1?[i&1==1]i
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=5100,XJQ=1e9+7; struct node{ll to,next; }a[N*2]; ll n,tot,ls[N],siz[N],f[N][N],ans,g[N],fac[N]; void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot; } void dp(ll x,ll fa){siz[x]=f[x][1]=1;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(y==fa)continue;dp(y,x);for(ll i=1;i<=siz[x];i++)g[i]=f[x][i],f[x][i]=0;for(ll j=1;j<=siz[x];j++){for(ll k=1;k<=siz[y];k++){(f[x][j+k]+=f[y][k]*g[j]%XJQ)%=XJQ;if((k&1)==0)(f[x][j]+=XJQ-f[y][k]*g[j]%XJQ*fac[k-1]%XJQ)%=XJQ;}}siz[x]+=siz[y];}return; } int main() {scanf("%lld",&n);for(ll i=1;i<n;i++){ll x,y;scanf("%lld%lld",&x,&y);addl(x,y);addl(y,x);}fac[0]=fac[1]=1;for(ll i=2;i<=n;i++)fac[i]=fac[i-2]*i%XJQ;dp(1,1);for(ll i=2;i<=n;i++)ans=(ans+f[1][i]*fac[i-1]%XJQ)%XJQ;printf("%lld",ans); }總結
以上是生活随笔為你收集整理的AT4352-[ARC101C] Ribbons on Tree【dp,容斥】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 找回qq密码的最快方法 有什么方法
- 下一篇: P3302-[SDOI2013]森林【主