Analysis
莫名其妙地被题面虐了一把
很好的一道结论题(?)
由朱刘算法的推论可知,如果除根节点外每个点都选择一条入边,由于没有环,因此一定会形成一个树形图
答案就是
∏
i
=
2
n
d
e
g
r
e
e
[
i
]
∏^n_{i=2}degree[i]
∏i=2ndegree[i] 其中degree[i]表示第i个点的入度
但是现在我们加入了一条边,图中就可能形成环
我们需要做的就是,依然用上述式子算答案,再减去不合法的环的情况
不合法 环的情况,就是
∑
S
是
原
图
中
y
→
x
的
一
条
路
径
的
点
集
∏
2
≤
j
≤
n
,
j
∉
S
d
e
g
r
e
e
j
\sum_{S是原图中y\rightarrow x的一条路径的点集}\prod_{2\leq j\leq n,j\notin S}degree_j
∑S是原图中y→x的一条路径的点集∏2≤j≤n,j∈/Sdegreej
翻译为人话,就是说:现在强制选择环,然后其他的点随便选的不合法方案数
那么我们的目标就是求出上面那个式子,怎么求呢?
可以考虑dp,状态转移
f i = ∑ j → i f j d e g r e e i f_i=\frac{\sum_{j\rightarrow i}f_j}{degree_i} fi=degreei∑j→ifj( j j j是可以到达 i i i的点)
Code
#include<bits/stdc++.h>
#define in read()
#define N 100009
#define M 200010
#define P 1000000007
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+ch-'0';ch=getchar();}
return f==1?res:-res;
}
int n,m,x,y,ans=1;
int f[N],inv[M];
int deg[N],__deg[N];
int nxt[M],to[M],head[N],ecnt=0;
inline void add(int x,int y){nxt[++ecnt]=head[x];head[x]=ecnt;to[ecnt]=y;}
inline int mul(int a,int b){return a*1ll*b%P;}
inline void topsort(){
queue<int> q;
for(int i=1;i<=n;++i)
if(!deg[i]) q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
f[u]=(f[u]*1ll*inv[__deg[u]])%P;
for(int e=head[u];e;e=nxt[e]){
int v=to[e];
f[v]=(f[u]+f[v])%P;
--deg[v];
if(!deg[v]) q.push(v);
}
}
}
inline void init(){
inv[1]=1;
for(int i=2;i<=m+1;++i)
inv[i]=(P-P/i)*1ll*inv[P%i]%P;
}
int main(){
n=in;m=in;x=in;y=in;
__deg[y]++;
init();
int i,j,k,u,v;
for(i=1;i<=m;++i){
u=in;v=in;
add(u,v);deg[v]++;__deg[v]++;
}
for(i=2;i<=n;++i) ans=mul(ans,__deg[i]);
if(y==1){
printf("%d",ans);
return 0;
}
f[y]=ans;
topsort();
printf("%d",(ans-f[x]+P)%P);
return 0;
}