zoukankan      html  css  js  c++  java
  • 【XSY1538】连在一起的幻想乡 数学 无向连通图计数

    题目大意

    ​  给你(n,p),求(n)个点组成的所有无向连通图的边数的平方和模(p)

    ​  (nleq 2000,pleq {10}^9)

    题解

    ​  设(m=frac{n(n-1)}{2},h0_n=n)个点无向图的个数,(h1_n=n)个点组成的所有无向图的边数之和,(h2_n=n)个点组成的所有无向图的边数的平方和,(f0_n=n)个点无向连通图的个数,(f1_n=n)个点组成的所有无向连通图的边数之和,(f2_n=n)个点组成的所有无向连通图的边数的平方和

      每条边可以选或不选,所以

    [h0_n=2^m ]

      因为每条边会被选中(2^{m-1})次,所以

    [h1_n=m2^{m-1} ]

      因为选(i)条边有(inom{m}{i})种方法,所以

    [h2_n=sum_{i=0}^mi^2(^m_{~i}) ]

      但是这个式子没法快速算出来。我们换一种思路。

    ​  我们枚举点(1)连出去的边的条数(i),根据({(x+sum y)}^2=x^2sum1+2xsum y+sum y^2),可得

    [h2_n=sum_{i=0}^{n-1}inom{n-1}{i}(h2_{n-1}+2ih1_{n-1}+i^2h0_{n-1}) ]

    ​  我们枚举与点(1)在同一个联通分量里的点的个数,计算联通分量数(geq2)的答案,然后用总的答案去减

    [f0_n=h0_n-sum_{i=1}^{n-1}inom{n-1}{i-1}f0_ih0_{n-i} ]

    [f1_n=h1_n-sum_{i=1}^{n-1}inom{n-1}{i-1}(f0_ih1_{n-i}+f1_ih0_{n-i}) ]

    [f2_n=h2_n-sum_{i=1}^{n-1}inom{n-1}{i-1}(f0_ih2_{n-i}+2f1_ih1_{n-i}+f2_ih0_{n-i}) ]

    ​  时间复杂度:(O(n^2))

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    #include<ctime>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    ll p;
    ll fp(ll a,ll b)
    {
    	ll s=1;
    	while(b)
    	{
    		if(b&1)
    			s=s*a%p;
    		a=a*a%p;
    		b>>=1;
    	}
    	return s;
    }
    ll c[2010][2010];
    ll f0[2010],f1[2010],f2[2010];
    ll h0[2010],h1[2010],h2[2010];
    int main()
    {
    //	freopen("road.in","r",stdin);
    	int n;
    	scanf("%d%lld",&n,&p);
    	int i,j;
    	c[0][0]=1;
    	for(i=1;i<=n;i++)
    	{
    		c[i][0]=1;
    		for(j=1;j<=i;j++)
    			c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
    	}
    	h0[1]=1;
    	h1[1]=h2[1]=0;
    	for(i=2;i<=n;i++)
    	{
    		int m=i*(i-1)/2;
    		h0[i]=fp(2,m);
    		h1[i]=m*fp(2,m-1)%p;
    		h2[i]=0;
    		for(j=0;j<=i-1;j++)
    			h2[i]=(h2[i]+c[i-1][j]*((h2[i-1]+2*j%p*h1[i-1]%p+j*j%p*h0[i-1]%p)%p)%p)%p;
    	}
    	f0[0]=f0[1]=1;
    	for(i=2;i<=n;i++)
    	{
    		f0[i]=h0[i];
    		f1[i]=h1[i];
    		f2[i]=h2[i];
    		for(j=1;j<=i-1;j++)
    		{
    			f0[i]=(f0[i]-c[i-1][j-1]*f0[j]%p*h0[i-j]%p)%p;
    			f1[i]=(f1[i]-c[i-1][j-1]*((f0[j]*h1[i-j]%p+f1[j]*h0[i-j]%p)%p)%p)%p;
    			f2[i]=(f2[i]-c[i-1][j-1]*((f0[j]*h2[i-j]%p+2*f1[j]*h1[i-j]%p+f2[j]*h0[i-j]%p)%p)%p)%p;
    		}
    	}
    	ll ans=(f2[n]%p+p)%p;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    win10下Anaconda3在虚拟环境python_version=3.5.3 中配置pyspark
    在Pycharm上编写WordCount程序
    ASP.NET Core读取AppSettings
    如何高逼格读取Web.config中的AppSettings
    C# 防止同时调用=========使用读写锁三行代码简单解决多线程并发的问题
    C#double转化成字符串 保留小数位数, 不以科学计数法的形式出现。
    Sql Server 里的向上取整、向下取整、四舍五入取整的实例!
    ECMAscript5 新增数组内函数
    js 严格模式
    js中数组去重
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8511163.html
Copyright © 2011-2022 走看看