luogu P3244 [HNOI2015]落忆枫音

传送门

md这题和矩阵树定理没半毛钱关系qwq

首先先不考虑有环,一个\(DAG\)个外向树个数为\(\prod_{i=2}^{n}idg_i(\)就是\(indegree_i)\),因为外向树每个点入度为一,对于一个点有入度个父亲可选,然后乘法原理起来就是答案

现在可能加一条边会有环,那么答案可以考虑总方案减不合法方案,不合法的有环方案就是环内的点连好了,然后剩下的点贡献方案,设\(s\)是个环,那么方案为\(\sum_{s}\prod_{i\notin s}idg_i=\sum_{s}\frac{\prod_{i=2}^{n}idg_i}{\prod_{i\in s}idg_i}=\prod_{i=2}^{n}idg_i\sum_{s}\frac{1}{\prod_{i\in s}idg_i}\)

后面那个东西,因为加了边\(x\rightarrow y\),所以一条\(y\)\(x\)可以确定一个环,那么以\(y\)为初始状态,可拓扑排序一遍dp出来方案

注意\(y=1\)的情况

#include<bits/stdc++.h>
#define LL long long
#define db double
#define il inline
#define re register

using namespace std;
const int N=1e5+10,mod=1e9+7;
il int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int to[N<<1],nt[N<<1],hd[N],dg[N],idg[N],tot;
void add(int x,int y){++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot,++dg[y];}
int n,m,u,v,f[N],inv[N];
queue<int> q;

int main()
{
    n=rd(),m=rd(),u=rd(),v=rd();
    for(int i=1;i<=m;++i)
    {
        int x=rd(),y=rd();
        add(x,y);
    }
    int ans=1;
    for(int i=2;i<=n;++i) ans=1ll*ans*(dg[i]+(v==i))%mod;
    if(v!=u&&v!=1)
    {
        memcpy(idg,dg,sizeof(dg));
        inv[0]=inv[1]=1;
        for(int i=2;i<=n+1;++i) inv[i]=(mod-1ll*mod/i*inv[mod%i]%mod)%mod;
        f[v]=1,q.push(1);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            f[x]=1ll*f[x]*inv[dg[x]+(x==v)]%mod;
            for(int i=hd[x];i;i=nt[i])
            {
                int y=to[i];
                f[y]=(f[y]+f[x])%mod,--idg[y];
                if(!idg[y]) q.push(y);
            }
        }
        ans=1ll*ans*(1-f[u]+mod)%mod;
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-02-25 20:14  ✡smy✡  阅读(117)  评论(1编辑  收藏  举报