1. 程式人生 > >[luogu3244 HNOI2015] 落憶楓音(容斥原理+拓撲排序)

[luogu3244 HNOI2015] 落憶楓音(容斥原理+拓撲排序)

沒有 容斥 mes ont 一行 www 只需要 a* ()

傳送門

Description

給你一張?n?個點?m?條邊的DAG,1?號節點沒有入邊。再向這個DAG中加入邊?x→y?,求形成的新圖中以?1?為根的外向樹形圖數 模?10^9+7?。

Input

輸入文件的第一行包含四個整數 n、m、x和y,依次代表楓葉上的穴位數、脈絡數,以及要添加的脈絡是從穴位 x連向穴位y的。 接下來 m行,每行兩個整數,由空格隔開,代表一條脈絡。第 i 行的兩個整數為ui和vi,代表第 i 條脈絡是從穴位 ui連向穴位vi的。

Output

輸出一行,為添加了從穴位 x連向穴位 y的脈絡後,楓葉上以穴位 1 為根的脈絡樹的方案數對 1,000,000,007取模得到的結果。

Sample Input

4 4 4 3
1 2
1 3
2 4
3 2

Sample Output

3

HINT

對於所有測試數據,1 <= n <= 100000,n - 1 <= m <= min(200000, n(n -1) / 2),

1 <= x, y, ui, vi <= n。

Solution

直接處理外向樹形圖的數目比較困難,考慮容斥,用 每個點選一條入邊的方案數 減去 每個點選一條入邊形成不了外向樹形圖的方案數 得到答案。
每個點選一條入邊的方案數直接求
對於無法形成外向樹形圖的情況顯然是出現了一個環(除自環)而我們知道x和y顯然就在環中,那麽我們只需要從y到x跑一個拓撲排序+dp求出y到x的路徑數所占總路徑數的比例即可

Code

//By Menteur_Hxy
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;
typedef long long LL;

int read() {
    int x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int N=100010,MOD=1000000007;
bool vis[N];
LL ans,du[N],f[N],de[N];
vector <int> V[N];
queue <int> Q;

LL qpow(LL a,LL b) {
    LL t=1;
    while(b) {
        if(b&1) t=t*a%MOD;
        a=a*a%MOD; b>>=1;
    }
    return t;
}

void dfs(int x) {
    int siz=V[x].size();
    F(i,0,siz-1) if(!vis[V[x][i]]) vis[V[x][i]]=1,dfs(V[x][i]);
}

int main() {
    int n=read(),m=read(),s=read(),t=read(),u,v;
    ans=du[1]=1; du[t]++;
    F(i,1,m) u=read(),v=read(),V[u].push_back(v),du[v]++;
    F(i,1,n) ans=ans*du[i]%MOD,du[i]=qpow(du[i],MOD-2);
    vis[t]=1; dfs(t);
    F(i,1,n) {
        int siz=V[i].size();
        F(j,0,siz-1) if(vis[i]&&vis[v=V[i][j]]) de[v]++;
    }
    f[t]=du[t]; Q.push(t);
    while(!Q.empty()) {
        u=Q.front(); Q.pop();
        int siz=V[u].size();
        F(i,0,siz-1) if(vis[v=V[u][i]]) {
            f[v]=(f[v]+f[u]*du[v])%MOD; 
            de[v]--;
            if(!de[v]) Q.push(v);
        }
    }
    printf("%lld",ans*(1-f[s]+MOD)%MOD);
    return 0;
}

[luogu3244 HNOI2015] 落憶楓音(容斥原理+拓撲排序)