• 7010. 2021.03.13【2021省赛模拟】graph


    (n)个点的图,每次随机两个点(u,v)(两者独立随机互不相干),连边((u,v)),问第一次联通的期望步数。

    (nle 100)


    讲阳间的(O(n^5))做法。

    (G_i)表示保持在恰好(i)个联通块的期望时间,(F_i)为至少。求(F_i)之后容斥得到(G_i)

    考虑把点划分成若干个块,保证块之间不连通,块内的点可以联通可以不联通。

    如果求出了这个东西的答案,则因为(F_n=sum_{i=n}^N S(N,i)G_i),斯特林反演得(G_n=sum_{i=n}^N s(N,i)F_i(-1)^{N-i})

    对于一个划分的方案,贡献为(frac{1}{1-frac{sum a_i^2}{n^2}}),其中(a_i)表示块大小。(可以看做后面的连边都要限制在每个块内,不发生块的合并,保持在这状态的期望步数)。

    可以dp计算:设(dp_{i,j,k})表示用了(i)个点形成了(j)个块,(sum a_i^2=k)的贡献(方案数,这个方案数和概率无关,它是用来处理“至少”的)。然后(F_j=sum dp_{n,j,k}frac{1}{1-frac{k}{n^2}})

    这个dp可以(O(n^5))算。因为有值的地方不会很多,所以时间约等于(O(n^4))

    题解做法:

    (dp_{n,k})(n)个点进行了(k)步不连通的概率。

    据此列出DP方程:

    [dp_{n,k}=sum_{i=1}^{n-1}sum_{j=0}^kinom{n-1}{i-1}(1-dp_{i,j})inom{k}{j}(frac{i}{n})^{2j}(frac{n-i}{n})^{2(k-j)} ]

    然后它发现可以表示成(dp_{n,k}=sum_{i=0}^{n^2-1}c_{n,i}(frac{i}{n^2})^k)的形式,可以归纳证明。

    讲真我觉如果是我,我肯定不会发现的。所以扩展性不太好。

    根据DP方程得到(c)的递推式,算出(c)就好了,时间(O(n^4))


    using namespace std;
    #include <bits/stdc++.h>
    #define N 105
    #define ll long long
    int n,mo;
    ll qpow(ll x,ll y=mo-2){
    	ll r=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			r=r*x%mo;
    	return r;
    }
    int dp[N][N*N];
    int s[N][N],C[N][N];
    ll f[N],g[N];
    int main(){
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    //	freopen("in.txt","r",stdin);
    	scanf("%d%d",&n,&mo);
    	C[0][0]=1;
    	for (int i=1;i<=n;++i){
    		C[i][0]=1;
    		for (int j=1;j<=i;++j)
    			C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    	}
    	s[0][0]=1;
    	for (int i=1;i<=n;++i)
    		for (int j=1;j<=i;++j)
    			s[i][j]=(s[i-1][j-1]+(ll)s[i-1][j]*(i-1))%mo;
    	dp[0][0]=1;
    	for (int j=0;j<n;++j){
    		static int _dp[N][N*N];
    		memset(_dp,0,sizeof _dp);
    		for (int i=j;i<n;++i)
    			for (int k=0;k<=i*i;++k)
    				if (dp[i][k]){
    					int tmp=dp[i][k];
    					for (int t=1;i+t<=n;++t)
    						_dp[i+t][k+t*t]=(_dp[i+t][k+t*t]+(ll)tmp*C[i+t-1][t-1])%mo;
    				}
    		memcpy(dp,_dp,sizeof _dp);
    		if (j+1>=2){
    			for (int k=1;k<n*n;++k)
    				if (dp[n][k])
    					(f[j+1]+=(ll)dp[n][k]*n*n%mo*qpow(n*n-k))%=mo;
    		}
    	}
    	for (int i=2;i<=n;++i)
    		for (int j=i;j<=n;++j)
    			(g[i]+=s[j][i]*f[j]%mo*(j-i&1?-1:1))%=mo;
    	ll ans=0;
    	for (int i=2;i<=n;++i)
    		ans+=g[i];
    	ans=(ans%mo+mo)%mo;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    2015年终总结
    mmzb游戏事故分析
    为sproto手写了一个python parser
    Lua小技巧
    Techparty-广州 10 月 31 日 Docker 专场沙龙 后记
    1password密码库格式更新
    SSL加密与系统时间
    webpack的学习使用三
    webpack的学习使用二
    webpack的学习使用一
  • 原文地址:https://www.cnblogs.com/jz-597/p/14532253.html
Copyright © 2020-2023  润新知