Orz PoPoQQQ:http://blog.csdn.net/popoqqq/article/details/45194103
用脉络树总数减去不合法的情况(即树上有环的情况),拓扑序DP,注意特判连的边指向1的情况
学到了新姿势:线性求逆元
原理: (假设现在要求a的逆元,x=Mod/a,y=Mod%a)
ax+y≡0→−ax≡y→a−1≡−x∗y−1
a
x
+
y
≡
0
→
−
a
x
≡
y
→
a
−
1
≡
−
x
∗
y
−
1
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110000;
const int maxm = 210000;
const ll Mod = 1e9+7;
queue<int>q;
struct edge
{
int y,nex;
edge(){}
edge(int a,int b){y=a;nex=b;}
}a[maxm]; int len,fir[maxn];
void ins(int x,int y){a[++len]=edge(y,fir[x]);fir[x]=len;}
ll N[maxn],f[maxn],d[maxn],dt[maxn];
int n,m,sx,sy;
ll ret;
void get_N()
{
N[1]=1;
for(ll i=2;i<=n;i++)
N[i]=((-(Mod/i)*N[Mod%i])%Mod+Mod)%Mod;
}
void solve()
{
f[sy]=ret; d[sy]--;
for(int i=1;i<=n;i++)
{
if(!d[i]) q.push(i);
dt[i]=d[i];
} d[sy]++;
while(!q.empty())
{
int x=q.front(); q.pop();
f[x]=(f[x]*N[d[x]])%Mod;
if(x==sx)break;
for(int k=fir[x];k;k=a[k].nex)
{
int y=a[k].y;
(f[y]+=f[x])%=Mod;
if(!(--dt[y])) q.push(y);
}
}
}
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
memset(fir,0,sizeof fir);len=0;
scanf("%d%d%d%d",&n,&m,&sx,&sy);get_N();
for(int i=1;i<=m;i++)
{
int lx,ly;
scanf("%d%d",&lx,&ly);
d[ly]++;ins(lx,ly);
}
ret=1ll; d[sy]++;
for(int i=2;i<=n;i++)ret=(ret*d[i])%Mod;
if(sy==1){printf("%lld\n",ret);return 0;}
solve();
printf("%lld\n",(ret-f[sx]+Mod)%Mod);
return 0;
}