zoukankan      html  css  js  c++  java
  • [luogu3244 HNOI2015] 落忆枫音(容斥原理+拓扑排序)

    传送门

    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;
    }
    
    版权声明:本文为博主原创文章,未经博主允许不得转载。 博主:https://www.cnblogs.com/Menteur-Hxy/
  • 相关阅读:
    CSS3新增文本属性
    CSS选择器
    【转】Java基础——面试题汇总
    【转】equals和==的区别
    【转】JRE和JDK的区别
    【转】深度学习常用的模型评估指标
    【转】使用Scanner输入字符串时next()和nextLine()区别
    JAVA操作ORACLE大对象
    ORACLE大对象存储
    iis是什么东西?
  • 原文地址:https://www.cnblogs.com/Menteur-Hxy/p/9379325.html
Copyright © 2011-2022 走看看