zoukankan      html  css  js  c++  java
  • CF1109D Sasha and Interesting Fact from Graph Theory

    CF1109D Sasha and Interesting Fact from Graph Theory

    这个 (D) 题比赛切掉的人基本上是 (C) 题的 (5,6) 倍...果然数学计数问题比数据结构更受欢迎...

    • 以下大致翻译自官方题解.
    • 枚举 (a o b) 路径上边的数目,记为 (edges) .
    • 先来考虑给定的两个点路径上的 (edges-1) 个点(不含 (a,b) )和 (edge) 条边.
      • 节点有(edges-1)个,顺序不同则最后的树不同,所以方案数为 (A(n-2,edges-1)) .
      • 边有 (edges) 条,边权 (v) 需满足(v in mathbb{N_+},v_1+v_2+...+v_{edges-1}+v_{edges}=m).用隔板法可知方案数,即解的组数为 (C(m-1,edges-1)).
    • 再来考虑其它的 (n-edges-1) 个点和 (n-edges-1) 条边.
      • 由于其它边的边权显然不影响合法性,可以随意赋 ([1,m]) 内的整数值,方案数为 (m^{n-edges-1}).
      • 剩下的点我们需要使它们形成一个森林,并将每颗树挂在 (a o b)(edges+1) 个点上.这等价于所有的 (n) 个点形成一个 (edges+1) 颗树的森林,那 (edges+1) 个点都属于不同的树,然后将这 (edges+1) 个点连接起来.根据广义(Cayley)定理,方案数为 ((edges+1) cdot n^{n-edges-2}) .

    广义 (Cayley) 定理:

    (n) 个标号节点形成一个有 (k) 颗树的森林,使得给定的 (k) 个点没有两个点属于同一颗树的方案数为(kcdot n^{n-k-1}.)

    证明可以用归纳法,对 (n) 归纳,枚举节点 (1) 的邻居即可得递推式,进而得出证明.

    • 那么我们就得到了在 (edges) 确定的情况下的答案:

    [f(edges)=A(n-2,edges-1) cdot C(m-1,edges-1)cdot m^{n-edges-1} cdot (edges+1) cdot n^{n-edges-2}. ]

    • 线性预处理 (m,n​) 的幂,阶乘及阶乘逆元,枚举 (edges​) 统计答案,时间复杂度为 (O(n+m)).
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define mp make_pair
    #define pii pair<int,int>
    inline int read()
    {
    	int x=0;
    	bool pos=1;
    	char ch=getchar();
    	for(;!isdigit(ch);ch=getchar())
    		if(ch=='-')
    			pos=0;
    	for(;isdigit(ch);ch=getchar())
    		x=x*10+ch-'0';
    	return pos?x:-x;
    }
    const int P=1e9+7;
    inline int add(int a,int b)
    {
    	return (a + b) % P;
    }
    inline int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    int fpow(int a,int b)
    {
    	int res=1;
    	while(b)
    		{
    			if(b&1)
    				res=mul(res,a);
    			a=mul(a,a);
    			b>>=1;
    		}
    	return res;
    }
    const int MAXN=1e6+10;
    int fac[MAXN],invfac[MAXN],mpow[MAXN],npow[MAXN];
    void init(int n,int m)
    {
    	int mx=max(n,m);
    	fac[0]=1;
    	for(int i=1;i<=mx;++i)
    		fac[i]=mul(fac[i-1],i);
    	invfac[mx]=fpow(fac[mx],P-2);
    	for(int i=mx-1;i>=0;--i)
    		invfac[i]=mul(invfac[i+1],i+1);
    	mpow[0]=npow[0]=1;
    	for(int i=1;i<=n;++i)
    		mpow[i]=mul(mpow[i-1],m);
    	for(int i=1;i<=n;++i)
    		npow[i]=mul(npow[i-1],n);
    }
    int A(int n,int m)
    {
    	if(n<m || n<0 || m<0)
    		return 0;
    	return mul(fac[n],invfac[n-m]);
    }
    int C(int n,int m)
    {
    	if(n<m || n<0 || m<0)
    		return 0;
    	return mul(fac[n],mul(invfac[n-m],invfac[m]));
    }
    int main()
    {
    	int n=read(),m=read();
    	int a=read(),b=read();
    	init(n,m);
    	int ans=0;
    	for(int edges=1;edges<n;++edges)
    		{
    			int tmp=mul(A(n-2,edges-1),C(m-1,edges-1));
    			tmp=mul(tmp,mpow[n-edges-1]);
    			tmp=mul(tmp,edges==n-1?1:mul(edges+1,npow[n-edges-2]));
    			ans=add(ans,tmp);
    		}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    <JZOJ5912>VanUSee
    <JZOJ5910>duliu
    <JZOJ5913>林下风气
    pytest学习笔记(二)
    试用saucelabs进行浏览器兼容性测试
    pytest学习笔记(一)
    SSM框架搭建,以及mybatis学习
    游戏2048的python实现
    使用svn在github上下载文件夹
    jenkins集成python的单元测试
  • 原文地址:https://www.cnblogs.com/jklover/p/10391064.html
Copyright © 2011-2022 走看看