zoukankan      html  css  js  c++  java
  • 「HNOI 2015」落忆枫音

    题目链接

    戳我

    (Description)

    给一张(n)割点(m)条边的(DAG),保证点(1)不存在入边,现在需要在(DAG)中加入一条不在原图中的边((x,y)),求这个有向图以(1)为根的树形图个数对(1e9+7)去模的结果

    (n<=100000,m<=200000)

    (Solution)

    我们首先来看看如果没有((x,y))这一条边的话,在(DAG)上的方案数为多少?

    [ans=prod_{i=1}^{n} vis[i] ]

    (vis)为,点的入度

    至于为什么?乘法原理就好了,很容易证明的.

    现在来看看有了((x,y))的限制如何处理?

    因为加入了这条边以后可能会存在环,所以不能单单这么算了,我们还应减去不合法的情况.那么不合法情况怎么算呢?

    我们还是令:

    [ans=prod_{i=1}^{n} vis[i] ]

    假设现在有一个环,中间的节点为:(a_1,a_2...a_k)

    则不合法的情况为:

    [frac{ans}{prod_{i=1}^kvis[i]} ]

    因为除了环的点的入度已经固定以外其他的可以随便选

    所以我们可以用(f[v]) 记录从(y)(vfrac{ans}{prod_{i=1}^k vis[i]})的值

    转移方程为(存在一条从(u->v)的路径):

    [f[u]=sum f[v] ]

    最后的答案就是:

    [prod_{i=1}^{n} (i==y)?vis[i+1]:vis[i]-f[x] ]

    注意一点要建反向边,因为要判断环.

    (Code)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int mod=1e9+7;
    int read() {
        int x=0,f=1;
        char c=getchar();
        while(c<'0'||c>'9') f=(c=='-')?-1:1,c=getchar();
        while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
        return x*f;
    }
    struct node {
        int to,next;
    }a[100010<<1];
    int vis[100010],head[100010],cnt,n,m,x,y,u,v,ans=1,sum=1,bj[100010],f[100010];
    void add(int x,int y){
        a[++cnt].to=y,a[cnt].next=head[x],head[x]=cnt;
    }
    int ksm(int a,int b){
        int ans=1;
        while(b){
    	    if(b&1)
    	        ans=ans*a%mod;
        	a=a*a%mod;
    	    b>>=1;
        }
        return ans%mod;
    }
    int inv(int x){
        return ksm(x,mod-2)%mod;
    }
    void dfs(int x){
        if(bj[x])
    	    return ;
        bj[x]=1;
        if(x==y){
    	    f[x]=sum*inv(vis[x])%mod;
    	    return ;
        }
        for(int i=head[x];i;i=a[i].next){
    	    int v=a[i].to;
    	    dfs(v);
    	    f[x]=(f[x]+f[v])%mod;
        }
        f[x]=f[x]*inv(vis[x])%mod;
    }
    main(){
        n=read(),m=read(),x=read(),y=read();
        for(int i=1;i<=m;i++)
    	    u=read(),v=read(),add(v,u),vis[v]++;
        vis[1]++;
        for(int i=1;i<=n;i++)
    	    sum=sum*vis[i]%mod,(i==y)?ans=ans*(vis[i]+1)%mod:ans=ans*vis[i]%mod;
        dfs(x);
        printf("%lld ",(ans-f[x]+mod)%mod);
    }
    
    
  • 相关阅读:
    mysql 导入报错(ERROR 1840 (HY000) at line 24: @@GLOBAL.GTID_PURGED can only be set when @@GLOBAL.GTID_E)
    Docker容器开机自动启动
    linux 查看内存条详情命令
    Linux 网络性能测试工具 iperf 的安装和使用
    redis基准性能测试
    pmm的安装,这里推荐下载官方提供的脚本,直接执行这个脚本就可以完成安装
    mysqlslap压力测试时出现"Can't connect to MySQL server"
    Linux监控工具介绍系列——iostat
    提高RabbitMQ的File descriptors
    python 打包
  • 原文地址:https://www.cnblogs.com/hbxblog/p/10411426.html
Copyright © 2011-2022 走看看