#dp#洛谷 3244 [HNOI2015]落忆枫音
分析
每个有入度的点可以选择任意一个父节点组成一棵树,那么原来的答案就是 \(\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]\),最后不合法的方案就是 \(dp[y]\)
代码
#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);
}