• [P3244][HNOI2015] 落忆枫音 (树上DAG+组合数)


    题意:给一个DAG,然后多加一条边,求在这个图中有多少种不同的生成树;

    解法:树上DAG+组合数;

    1.树上DAG:因为在DAG上多加了一条边,所以原图会出现环,那么多算的答案就是 rel = ans / ( 环上的点的入度的累乘 ),最后的答案就是 ans-rel(要注意,多加了一条边后,图上可能不止一个环,此时的 rel就是∑tot,tot = ans / ( 环上的点的入度的累乘 ));我们可以在计算这个多算出来的贡献时使用 DP,而在 DP时可以在原图上进行,因为我们的结束边界是多加的那一条边的 end;

    2.组合数:当图还是一个DAG时,由乘法原理可得 ans就是所有入度的乘积(这其实是一个定理——朱刘定理);

    附上代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #define ll long long
    using namespace std;
    const int N = 2e5+10;
    const int mod = 1e9+7;
    
    inline int read(){
        int ref=0,x=1;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) ref=ref*10+ch-'0',ch=getchar();
        return ref*x;
    }
    
    int n,m,xx,yy;
    struct edge{
        int next,to;
    }a[N<<4];
    int cnt,head[N<<4],x[N],y[N];
    int ru[N],vis[N],f[N];
    ll ans=1,sum=1;
    
    void add(int u,int v){
        a[++cnt]=(edge){head[u],v};
        head[u]=cnt;
    }
    
    ll ksm(ll a,ll b){
        ll rel=1;
        a%=mod;
        while(b){
            if(b&1) rel=(rel*a)%mod;
            a=(a*a)%mod;
            b>>=1;
        }
        return rel;
    }
    
    ll inv(ll a){ return ksm(a,mod-2); }
    
    void dfs(int x){
        if(vis[x]) return ;
        vis[x]=1;
        if(x==yy){
            f[x]=(sum*inv(ru[x]))%mod;
            return ;
        }
        for(int i=head[x];i;i=a[i].next){
            int v=a[i].to;
            dfs(v);
            f[x]=(f[x]+f[v])%mod;//乘法具有分配律,不影响最终的答案 
        }
        f[x]=(f[x]*inv(ru[x]))%mod;
    }
    
    int main()
    {
        n=read(),m=read(),xx=read(),yy=read();
        ru[1]++;
        for(int i=1;i<=m;++i){
            int x,y;
            x=read(),y=read();
            add(y,x);
            ru[y]++;
        }
        for(int i=1;i<=n;++i){
            if(i==yy) ans=(ans*(ru[i]+1))%mod;
            else ans=(ans*ru[i])%mod;
            sum=(sum*ru[i])%mod;
        }
        dfs(xx);
        if(xx==yy||yy==1) printf("%lld",sum%mod);
        else printf("%lld",(ans-f[xx]+mod)%mod);
        return 0;
    }
  • 相关阅读:
    leetcode 54. 螺旋矩阵 js高效实现
    leetcode 141. 环形链表 js 实现
    通过 BFC 实现页面布局
    leetcode 1351. 统计有序矩阵中的负数 js实现
    js 实现元素拖拽
    如何在 chrome控制台快速获取某段 html?
    leetcode 160. 相交链表 js 实现
    leetcode 70. 爬楼梯 js实现
    nodejs中事件循环中的执行顺序
    leetcode 300. 最长递增子序列 js 动态规划实现
  • 原文地址:https://www.cnblogs.com/nnezgy/p/11469152.html
Copyright © 2020-2023  润新知