Projecteuler522 Hilbert's Blackout
Hilbert's Blackout
\(n\) 个点,每个点随机连向和它不同的点。定义一个图的代价为最少所需点数使得改这么多个点的出边后能让它变成一个大环。
求所有图的总代价。\(n=10^7\)。
题解
https://titanwolf.org/Network/Articles/Article?AID=0d201ef5-6157-4a52-861a-11d934f87266
For a component, if
-
it's a cycle of size < n, we need to rewire 1 floor;
-
it's a cycle of size n, we've finished!
-
otherwise, we need to rewire \(\sum (\max(indeg_i, outdeg_i) - 1)\) floors.
根据期望的线性性,我们仍然可以把不同种的贡献分开计算。
算环的式子:
\[\sum_{i=2}^{n-2}\binom{n}{i}(i-1)!\times (n-i-1)^{n-i}
\]
先枚举环的大小,枚举到 \(n-2\) 是因为剩余一个点的时候它只能自己连向自己。然后乘上环的组成,环上的顺序。再乘上其他点的连边方式。
算非环连通块的式子:
\[\sum_{i=2}^{n-1}(i-1)\times n\binom{n-1}{i}\times (n-1)(n-2)^{n-1-i}
\]
枚举入度的大小,乘上固有贡献。然后乘上被连的点是哪个,连边的点的组成。再乘上被连的点连向哪个,其他的点的连边方式。
CO int N=12344321+10;
int fac[N],ifac[N];
IN int binom(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int main(){
int n=12344321;
fac[0]=1;
for(int i=1;i<=n;++i) fac[i]=mul(fac[i-1],i);
ifac[n]=fpow(fac[n],mod-2);
for(int i=n-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
int ans=0;
for(int i=2;i<=n-2;++i)
ans=add(ans,mul(binom(n,i),mul(fac[i-1],fpow(n-i-1,n-i))));
for(int i=2;i<=n-1;++i)
ans=add(ans,mul(i-1,mul(binom(n-1,i),mul(fpow(n-2,n-1-i),mul(n-1,n)))));
printf("%d\n",ans);
return 0;
}
上课的时候杜老师讲代价=叶子个数+环个数。然后说算入度太麻烦。
但是当只有一个环的时候,代价要-1。这样反而不好计算了。
静渊以有谋,疏通而知事。