title
简化题意:
给定一张有向无环图,现在要求加入一条边,求加入后以 1 为根的树形图个数。
analysis
首先,不考虑这条加进来的边,这张图是个 \(DAG\)(废话)。
那么根据朱刘算法的推论可知:如果除根节点外每个点都选择一条入边,由于没有环,因此一定会形成一个树形图。
所以
\[ ans=\prod_{i=2}^n In[i],其中In[i]表示第i个点的入度 \]
现在,把这条边加进来,那么我们用上面的公式统计的话,就会有一些不合法的情况,我们需要把他减去。
如果这种情况不合法,那么一定会形成一个环,且环包括这条心加入的边。
所以我们要减去的情况就是:
\[ \sum_{S是原图y\to x的一条路径的点集}\prod_{2\leq j\leq n,j\notin S}In[j] \]
那么我们就可以 \(Dp\) 求解了,
状态:设 \(f_i\) 表示 \(\sum_{S是原图y\to x的一条路径的点集}\prod_{2\leq j\leq n,j\notin S}In[j]\);
状态转移方程:
\[ f_i=\frac{\sum_{j\to i}f[j]}{In[i]} \]
初值:
\[ f_T=\frac{\prod_{i=2}^n In[i]}{In[T]} \]
注意 \(T=1\) 的时候需要特判。
code
#include<bits/stdc++.h>
typedef long long ll;
const int maxm=2e5+10,mod=1e9+7;
namespace IO
{
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x,char str)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++=str;
}
}
using IO::read;
using IO::write;
int ver[maxm],Next[maxm],head[maxm],len;
inline void add(int x,int y)
{
ver[++len]=y,Next[len]=head[x],head[x]=len;
}
int In[maxm],b[maxm],n,m,S,T;;
ll f[maxm],inv[maxm], ans=1;
inline void Dp()
{
f[T]=ans; std::queue<int>q;
for (int i=1; i<=n; ++i)
if (!In[i]) q.push(i);
while (!q.empty())
{
int x=q.front();
q.pop();
f[x]=f[x]*inv[b[x]]%mod;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
f[y]=(f[y]+f[x])%mod;
if (!--In[y]) q.push(y);
}
}
}
int main()
{
read(n);read(m);read(S);read(T);
inv[1]=1;
for (int i=2; i<=m+1; ++i) inv[i]=(-inv[mod%i]*(ll)(mod/i)%mod+mod)%mod;//逆元
for (int i=1,x,y; i<=m; ++i) read(x),read(y),add(x,y),++In[y];
++In[T];
for (int i=1; i<=n; ++i) b[i]=In[i];
for (int i=2; i<=n; ++i) ans=ans*(ll)In[i]%mod;
--In[T];
if (T==1) { write(ans,'\n'), IO::flush(); exit(0); }//特判
Dp();
ans=(ans-f[S]+mod)%mod;//减去不合法的方案
write(ans,'\n');
IO::flush();
return 0;
}