[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);
}
原文地址:https://www.cnblogs.com/wwlwQWQ/p/14070625.html