[HNOI2015] BZOJ 4011 落忆枫音 - dp

121 篇文章 0 订阅
40 篇文章 0 订阅

考虑依然用随便选的答案减去含环的答案。
含环的答案就是\prod_{x不在环上}#{x的入度},也就是所以点的度数的乘积除以在环上的点答案,对环做dp即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
#define N 100010
#define M 200010
#define mod 1000000007
#define lint long long
#define clr(a,n) memset(a,0,sizeof(int)*((n)+1))
#define inv(x) fast_pow(x,mod-2)
using namespace std;
inline int inn()
{
    int x,ch;while((ch=gc)<'0'||ch>'9');
    x=ch^'0';while((ch=gc)>='0'&&ch<='9')
        x=(x<<1)+(x<<3)+(ch^'0');return x;
}
inline int mol(int x) { return x%=mod,(x<0?x+mod:x); }
struct edges{
    int to,pre;
}e[M];int h[N],d[N],dv[N],tms[N],etop,u[M],v[M],dp[N];queue<int> q;
inline int add_edge(int u,int v) { return e[++etop].to=v,e[etop].pre=h[u],h[u]=etop; }
inline int fast_pow(int x,int k,int ans=1)
{   for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int toposort(int s,int n,int ans=1)
{
    while(!q.empty()) q.pop();int c=0;
    for(int i=1;i<=n;i++) if(!d[i]) q.push(i);
    for(int i=2;i<=n;i++) ans=(lint)ans*d[i]%mod;
    while(!q.empty())
    {
        int x=q.front();tms[++c]=x,q.pop();
        for(int i=h[x],y;i;i=e[i].pre)
            if(!(--d[y=e[i].to])) q.push(y);
    }
    return c<n?ans=0:ans;
}
inline int getans(int s,int t,int n)
{
    clr(dp,n),dp[s]=1;
    for(int i=1;i<=n;i++) dv[i]=inv(d[i]);
    for(int i=2;i<=n;i++) dp[s]=(lint)dp[s]*d[i]%mod;
    for(int j=1,x=0;j<=n;j++) if(dp[x=tms[j]])
    {
        dp[x]=(lint)dp[x]*dv[x]%mod;
        for(int i=h[x];i;i=e[i].pre)
            (dp[e[i].to]+=dp[x])%=mod;
    }
    return dp[t];
}
int main()
{
    int n=inn(),m=inn(),x=inn(),y=inn(),ans=1;
    for(int i=1;i<=m;i++) u[i]=inn(),v[i]=inn();
    for(int i=1;i<=m;i++) add_edge(u[i],v[i]),d[v[i]]++;
    add_edge(x,y),d[y]++;
    if(ans=toposort(1,n)) return !printf("%d\n",ans);
    clr(h,n),etop=0,clr(d,n);
    for(int i=1;i<=m;i++) add_edge(u[i],v[i]),d[v[i]]++;
    toposort(1,n),clr(d,n),d[y]++,ans=1;
    for(int i=1;i<=m;i++) d[v[i]]++;
    for(int i=2;i<=n;i++) ans=(lint)ans*d[i]%mod;d[y]--;
    return !printf("%d\n",mol(ans-getans(y,x,n)));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值