• bzoj 4011


    看了好多篇题解才看懂的题,我实在太菜了...

    首先根据一个我不知道的算法,可以证明在没有加入新的边的时候,原图的所有生成树的方案数就是所有点(除1以外)的度之积

    那么在新加入这条边之后,我们仍然可以这样计算,但是会产生一种问题:就是会出现环!

    所以我们需要利用一些容斥,把不合法的情况去掉

    接下来我们考虑如何算出不合法的情况

    由于原图是一个有向无环图,所以在原图中怎么选都不会出现环,所以多的一条边一定在环内!

    那么如果出现了环,一定是从多的边的终点到起点的一条路径

    所以我们只需要找出终点到起点的路径数量即可

    那么就进行一个拓扑排序求一下即可

    考虑一下怎么求:

    首先记状态:dp[i]表示从终点到i的路径数量

    然后考虑初值:dp[ed]=初始方案/终点入度

    (关于这里为什么要除掉一个入度:因为原来的初始方案中是包含这一点的入度的,所以要除掉这个入度)

    最后ans去掉这一部分即可

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define mode 1000000007
    #define ll long long
    using namespace std;
    struct Edge
    {
    	int next;
    	int to;
    }edge[200005];
    int n,m,st,ed;
    ll inr[100005];
    ll rinr[100005];
    int head[100005];
    ll inv[300005];
    int cnt=1;
    ll ans=1;
    ll dp[100005];
    void init()
    {
    	inv[0]=inv[1]=1;
    	for(int i=2;i<=300000;i++)
    	{
    		inv[i]=(mode-mode/i)*inv[mode%i]%mode;
    	}
    	memset(head,-1,sizeof(head));
    	cnt=1;
    }
    void add(int l,int r)
    {
    	edge[cnt].next=head[l];
    	edge[cnt].to=r;
    	head[l]=cnt++;
    }
    ll bfs()
    {
    	dp[ed]=ans;
    	queue <int> M;
    	for(int i=1;i<=n;i++)
    	{
    		if(!inr[i])
    		{
    			M.push(i);
    		}
    	}
    	while(!M.empty())
    	{
    		int u=M.front();
    		M.pop();
    		dp[u]*=inv[rinr[u]];
    		dp[u]%=mode;
    		for(int i=head[u];i!=-1;i=edge[i].next)
    		{
    			int to=edge[i].to;
    			dp[to]+=dp[u];
    			dp[to]%=mode;
    			inr[to]--;
    			if(!inr[to])
    			{
    				M.push(to);
    			}
    		}
    	}
    	return ((ans-dp[st])%mode+mode)%mode;
    }
    int main()
    {
    	scanf("%d%d%d%d",&n,&m,&st,&ed);
    	init();
    	rinr[ed]=1;
    	for(int i=1;i<=m;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		inr[y]++;
    		rinr[y]++;
    	}
    	for(int i=2;i<=n;i++)
    	{
    		ans*=rinr[i];
    		ans%=mode;	
    	}
    	if(ed==1)
    	{
    		printf("%lld
    ",ans);
    	}else
    	{
    		printf("%lld
    ",bfs());
    	}
    	return 0;
    }
  • 相关阅读:
    大型网站动态应用系统架构(转)
    [转]thinkphp在iis下的rewrite伪静态的配置方法
    [转]WEB安全编程技术规范(V1.0)
    『MXNet』第八弹_数据处理API_下_Image IO专题
    『TensorFlow』变量初始化
    『TensorFlow』线程控制器类&变量作用域
    『Python CoolBook』Cython_高效数组操作
    『Python CoolBook』Cython
    『流畅的Python』第5章笔记_一等函数
    『MXNet』第十弹_物体检测SSD
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10764141.html
Copyright © 2020-2023  润新知