#dp#洛谷 3244 [HNOI2015]落憶楓音
阿新 • • 發佈:2022-03-22
分析
每個有入度的點可以選擇任意一個父節點組成一棵樹,那麼原來的答案就是 \(\prod_{i=2}^ndeg[i]\)
現在多了一條邊,如果邊的終點是1或者它是一個自環那麼可以不用管這條邊。
然後先把這條邊加上再減去不合法的方案,可以發現不合法的方案就是選出任意一個環,它貢獻的方案數就是 \(\Large \frac{\prod_{i=2}^ndeg[i]}{\prod_{i\in it}deg[i]}\)
那麼設 \(dp[y]\) 表示 \(y\) 到 \(x\) 的環的方案數,\(dp[y]=\frac{1}{deg[y]}\sum{dp[y']}\)
\(dp[x]=\prod_{i=2}^ndeg[i]\)
程式碼
#include <cstdio> #include <cctype> using namespace std; const int N=100011,mod=1000000007; struct node{int y,next;}e[N<<1]; int dp[N],ieg[N],ans=1,v[N],sum=1,as[N],deg[N],n,m,X,Y; int iut(){ int ans=0; char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=ans*10+c-48,c=getchar(); return ans; } void print(int ans){ if (ans>9) print(ans/10); putchar(ans%10+48); } int ksm(int x,int y){ int ans=1; for (;y;y>>=1,x=1ll*x*x%mod) if (y&1) ans=1ll*ans*x%mod; return ans; } void Mo(int &x,int y){x=x+y>=mod?x+y-mod:x+y;} void dfs(int x){ if (v[x]) return; v[x]=1; for (int i=as[x];i;i=e[i].next) dfs(e[i].y),Mo(dp[x],dp[e[i].y]); dp[x]=1ll*dp[x]*ieg[x]%mod; } int main(){ n=iut(),m=iut(),X=iut(),Y=iut(); for (int i=1;i<=m;++i){ int x=iut(),y=iut(); e[i]=(node){y,as[x]},as[x]=i; ++deg[y]; } if (X==Y||Y==1){ for (int i=2;i<=n;++i) ans=1ll*ans*deg[i]%mod; return !printf("%d",ans); } for (int i=2;i<=n;++i){ sum=1ll*sum*deg[i]%mod; if (i!=Y) ans=1ll*ans*deg[i]%mod; } ieg[1]=1,Mo(ans,sum); for (int i=2;i<=n;++i) ieg[i]=1ll*ieg[i-1]*deg[i]%mod; ieg[n]=ksm(ieg[n],mod-2); for (int i=n,now=ieg[n];i>1;--i){ ieg[i]=1ll*ieg[i-1]*now%mod; now=1ll*now*deg[i]%mod; } dp[X]=sum,dfs(Y),Mo(ans,mod-dp[Y]); return !printf("%d",ans); }