• [2020多校联考]环


    Solution

    每两个点都有一条有向边,所以是一个完全有向图。每次走最短的路径,所以是三元环(手玩样例亦可得)。
    所以问题就转换为了统计有向图三元环期望个数。考虑转换补集的思想,一共可能有 (inom{n}{3}) 个环,再减去不是环的。发现如果三个点构不成环,那么一定有其中一个点有两条出边。

    对于已知的点和边,统计每个点的出度 (d_i),那么一定有 (inom{d_i}{2}) 个三元组构不成环,需减去。(已经可以得 (20) 分了)
    现在加入随机边的贡献。每条边的方向是等概率的,对于一个点 (i),它会向其它 (n-1) 个点连边,统计已经确定的且和 (i) 相连的边条数 (s_i),那么剩下的 (n-s_i-1) 条边就有 (2^{n-s_i-1}) 种情况,枚举有其中 (j) 条是 (i) 的出边的情况。这 (j) 条边会和现有的 (d_i) 条出边产生贡献,会造成 (d_i imes j) 个三元组构不成环,概率是 (frac{inom{n-s_i-1}{j}}{2^{n-s_i-1}})。所以要减去

    [sum_{j=0}^{n-s_i-1} frac{inom{n-s_i-1}{j}}{2^{n-s_i-1}} imes d_i imes j ]

    化简

    [frac{d_i}{2^{n-s_i-1}}sum_{j=0}^{n-s_i-1} inom{n-s_i-1}{j} imes j=frac{d_i}{2^{n-s_i-1}}sum_{j=0}^{n-s_i-1} inom{n-s_i-2}{j-1} imes (n-s_i-1) ]

    中间再用二项式定理搞掉

    [=frac{d_i}{2^{n-s_i-1}} imes 2^{n-s_i-2} imes(n-s_i-1)=frac{d_i(n-s_i-1)}{2} ]

    再考虑两条随机边相互之间的贡献。同样枚举个数,有 (j) 条随机边是出边,那么就少 (inom{j}{2}) 个环,加上概率,为

    [sum_{j=0}^{n-s_i-1}frac{inom{n-s_i-1}{j}}{2^{n-s_i-1}} imes inom{j}{2} ]

    (inom{j}{2}) 拆了,用上面相同的方式化简

    [frac{n-s_i-1}{2^{n-s_i}}sum_{j=0}^{n-s_i-1} inom{n-s_i-2}{j-1} imes (j-1)=frac{(n-s_i-1)(n-s_i-2)}{2^{n-s_i}}sum_{j=0}^{n-s_i-1} inom{n-s_i-3}{j-2} ]

    [=frac{(n-s_i-1)(n-s_i-2)}{2^{n-s_i}} imes 2^{n-s_i-3}=frac{(n-s_i-1)(n-s_i-2)}{8} ]

    所以最后要求的值就是

    [inom{n}{3}-sum_{i=1}^{n} [inom{d_i}{2}+frac{d_i(n-s_i-1)}{2}+frac{(n-s_i-1)(n-s_i-2)}{8}] ]

    #include<stdio.h>
    #define Mod 1000000007
    #define N 100007
    #define ll long long
    
    inline int read(){
        int x=0,flag=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    ll qpow(ll x,ll y){
        ll ret=1,cnt=0;
        while(y>=(1LL<<cnt)){
            if(y&(1LL<<cnt)) ret=(ret*x)%Mod;
            x=(x*x)%Mod,cnt++;
        }
        return ret;
    }
    
    ll n,e;
    ll d[N],s[N];
    int main(){
        freopen("circle.in","r",stdin);
        freopen("circle.out","w",stdout);
        n=read(),e=read();
        for(int i=1;i<=e;i++){
            int u=read(),v=read();
            d[u]++,s[u]++,s[v]++;
        }
        ll ans=n*(n-1)%Mod*(n-2)%Mod*qpow(6LL,Mod-2)%Mod;
        ll n2=qpow(2LL,Mod-2),n8=qpow(8LL,Mod-2);
        for(int i=1;i<=n;i++){
            ll ret=d[i]*(d[i]-1)%Mod*n2%Mod;
            ret=(ret+d[i]*(n-s[i]-1)%Mod*n2%Mod)%Mod;
            ret=(ret+(n-s[i]-1)*(n-s[i]-2+Mod)%Mod*n8%Mod)%Mod;
            ans=((ans-ret)%Mod+Mod)%Mod;
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    MySQL与OLAP:分析型SQL查询最佳实践探索
    创建与删除索引
    第三方推送-个推使用
    test
    图床_搭建本地yum仓库及自制rpm包(无需镜像)
    图床_有趣的linux命令行工具-lolcat
    图床_fdisk一键操作分区-无需脚本
    图床_将你的CentOS 7 配置yum源
    图床_使用Putty远程连接管理Linux实践
    图床_使用Xshell远程连接管理Linux实践
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/14070625.html
Copyright © 2020-2023  润新知