BZOJ 4011 [HNOI2015]落忆枫音

本文介绍了一种针对拓扑图的DP算法,通过计算各节点的入度来解决有向无环图上的计数问题。特别讨论了如何处理加边后形成的环,并给出了一段C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

拓扑图DP

对于拓扑图,deg[i]表示i的入度,根为1,答案就是 ni=2deg[i]

即除根节点外,每个点都选择一条入边,由于图是DAG,因此一定会形成一个树形图(听说这是朱刘算法的推论?)

考虑加完边之后有环怎么办?只要在答案里减去环的贡献即可。如何求环的贡献?当环的边全部被选时,方案数肯定是所有非环上点(除了根1)的入度之积。脑补即可证明。因此需要特判y=1。

附大爷题解:http://blog.youkuaiyun.com/popoqqq/article/details/45194103

#include<cstdio>
#include<queue>
#define ll long long
#define N 100005
#define MOD 1000000007
#define M 200005
using namespace std;
struct edge{int next,to;}e[M];
ll f[N];
int last[N], ecnt=1, deg[N], in[N], inv[M], n, m, x, y; ;
void add(int a, int b)
{
    e[++ecnt]=(edge){last[a],b};
    last[a]=ecnt;
}
void init()
{
    inv[1]=1;
    for(int i = 2, ii = m+1; i <= ii; i++)
        inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
}
void DP()
{
    init();
    queue<int> q;
    q.push(1);
    f[y]=1; 
    while(!q.empty())
    {
        int u = q.front();
        if(x==u)break;
        q.pop();
        f[u]=f[u]*inv[deg[u]]%MOD;
        for(int i = last[u]; i; i=e[i].next)
        {
            int v=e[i].to;
            f[v]=(f[v]+f[u])%MOD;
            in[v]--;
            if(!in[v])
                q.push(v);
        }
    }
    f[x]=f[x]*inv[deg[x]]%MOD;
}
int main()
{
    ll ans=1;
    scanf("%d%d%d%d",&n,&m,&x,&y);
    deg[y]++;
    for(int i = 1; i <= m; i++)
    {
        int a, b;
        scanf("%d%d",&a,&b);
        add(a,b);
        deg[b]++;
        in[b]++;
    }
    for(int i = 2; i <= n; i++)
        ans=ans*deg[i]%MOD;
    if(y==1)
    {
        printf("%lld\n",ans);
        return 0;
    }
    DP();
    printf("%lld\n",(ans-ans*f[x]%MOD+MOD)%MOD);
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值