【BZOJ4011】【HNOI2015】落忆枫音

本文探讨了一个特定的图论问题:如何计算在一个有向无环图(脉络图)中添加一条新边后,以特定节点为根的脉络树的数量。文章介绍了一种结合动态规划和拓扑排序的方法来解决这个问题,并提供了详细的实现步骤。

Description

不妨假设枫叶上有 n个穴位,穴位的编号为 1 ~  n。有若干条有向的脉络连接着这些穴位。穴位和脉络组成一个有向无环图——称之为脉络图(例如图 1),穴位的编号使得穴位 1 没有从其他穴位连向它的脉络,即穴位 1 只有连出去的脉络;由上面的故事可知,这个有向无环图存在一个树形子图,它是以穴位 1为根的包含全部n个穴位的一棵树——称之为脉络树(例如图 2和图 3给出的树都是图1给出的脉络图的子图);值得注意的是,脉络图中的脉络树方案可能有多种可能性,例如图2和图 3就是图 1给出的脉络图的两个脉络树方案。 
       
脉络树的形式化定义为:以穴位 r 为根的脉络树由枫叶上全部 n个穴位以及 n-  1 条脉络组成,脉络树里没有环,亦不存在从一个穴位连向自身的脉络,且对于枫叶上的每个穴位 s,都存在一条唯一的包含于脉络树内的脉络路径,使得从穴位r 出发沿着这条路径可以到达穴位 s。 现在向脉络图添加一条与已有脉络不同的脉络(注意:连接 2个穴位但方向不同的脉络是不同的脉络,例如从穴位3到4的脉络与从4到3的脉络是不同的脉络,因此,图 1 中不能添加从 3 到 4 的脉络,但可添加从 4 到 3 的脉络),这条新脉络可以是从一个穴位连向自身的(例如,图 1 中可添加从 4 到 4 的脉络)。原脉络图添加这条新脉络后得到的新脉络图可能会出现脉络构成的环。 请你求出添加了这一条脉络之后的新脉络图的以穴位 1 为根的脉络树方案数。由于方案可能有太多太多,请输出方案数对 1,000,000,007 取模得到的结果。 

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。
题解
dp+拓扑。思路题。
先考虑一个简单的问题,如果不加这条新边,那么方案数是除了1号点之外所有点的入度相乘。现在加上这条新边,还这样乘完,会因为有环而多算。所以要减去这些多算的。(假设添加的边是s->t,那么对于原图中t->s的每一条路径.不在该路径上的点的入度的乘积的和就是成环的方案数.)我也不知道为什么,如果哪位大佬知道为什么,求教。。。
先假设明白了吧,这样用dp[i]表示t到i的路径数,由于要转移到j,所以要出去刚才的贡献。在mod意义下就是乘以它的逆元。。先线性求逆元。再拓扑dp一下就行了。神题
ni[i]=-(mod/i)*(ni[mod%i])%mod;

证明:强博客:http://blog.miskcoo.com/2014/09/linear-find-all-invert
这个做法实际上是这样的,首先 111(modp)
然后我们设 p=ki+r, r<i, 1<i<p

再将这个式子放到modp

意义下就会得到

ki+r0(modp)

两边同时乘上 i1r1

就会得到

kr1+i1i1i10kr1pi(pmodi)1(modp)(modp)(modp) 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define mod 1000000007
using namespace std;
const int maxn=200010;
queue<int>q;
int pre[maxn*2],other[maxn*2],last[maxn*2],num;
int ru[maxn*2],in[maxn*2];
ll ni[maxn*2],dp[maxn],ans;
int n,m,s,t;
void add(int x,int y){
    num++;
    pre[num]=last[x];
    last[x]=num;
    other[num]=y;
}
void niyuan(){
    ni[1]=1;
    for(int i=2;i<=m+1;i++)
    ni[i]=-(mod/i)*(ni[mod%i])%mod;
}
void tuopu(){
    for(int i=1;i<=n;i++)
    if(!in[i]) q.push(i);
    dp[t]=ans;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        dp[u]=(dp[u]*ni[in[u]])%mod;
        for(int i=last[u];i;i=pre[i]){
            int v=other[i];
            ru[v]--;
            dp[v]=(dp[v]+dp[u])%mod;
            if(!ru[v]){
                q.push(v);
            }
        }
    }
}
int main(){
    int x,y;
    cin>>n>>m>>s>>t;
    niyuan();
    for(int i=1;i<=m;i++){
        cin>>x>>y;
        add(x,y);
        ru[y]++;in[y]++;
    }
    in[t]++;
    ans=1;
    for(int i=2;i<=n;i++){
        ans=(ans*in[i])%mod;
    }
    if(t==1){
        printf("%lld",ans);
        return 0;
    }
    tuopu();
    printf("%lld\n",(ans-dp[s]+mod)%mod);
    return 0;
}


【SCI一区复现】基于配电网韧性提升的应急移动电源预配置和动态调度(下)—MPS动态调度(Matlab代码实现)内容概要:本文档围绕“基于配电网韧性提升的应急移动电源预配置和动态调度”主题,重点介绍MPS(Mobile Power Sources)动态调度的Matlab代码实现,是SCI一区论文复现的技术资料。内容涵盖在灾害或故障等极端场景下,如何通过优化算法对应急移动电源进行科学调度,以提升配电网在突发事件中的恢复能力与供电可靠性。文档强调采用先进的智能优化算法进行建模求解,并结合IEEE标准测试系统(如IEEE33节点)进行仿真验证,具有较强的学术前沿性和工程应用价值。; 适合人群:具备电力系统基础知识和Matlab编程能力,从事电力系统优化、配电网韧性、应急电源调度等相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于复现高水平期刊(SCI一区、IEEE顶刊)中关于配电网韧性与移动电源调度的研究成果;②支撑科研项目中的模型构建与算法开发,提升配电网在故障后的快速恢复能力;③为电力系统应急调度策略提供仿真工具与技术参考。; 阅读建议:建议结合前篇“MPS预配置”内容系统学习,重点关注动态调度模型的数学建模、目标函数设计与Matlab代码实现细节,建议配合YALMIP等优化工具包进行仿真实验,并参考文中提供的网盘资源获取完整代码与数据。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值