SRM578(多校联考T2)(组合计数)

n n n 个点 m m m 条边,前 k k k 个点的度数均为 2 2 2 的无向连通图个数,无重边自环。
1 ≤ n , m ≤ 50 , 0 ≤ k ≤ 2 1\le n,m \le 50,0\le k\le 2 1n,m50,0k2


无脑讨论就行了。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define ll long long
namespace io {
	const int SIZE = (1 << 21) + 1;
	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
	// getchar
	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
	// print the remaining part
	inline void flush () {
		fwrite (obuf, 1, oS - obuf, stdout);
		oS = obuf;
	}
	// putchar
	inline void putc (char x) {
		*oS ++ = x;
		if (oS == oT) flush ();
	}
	// input a signed integer
	template <class I>
	inline void gi (I &x) {
		for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
		for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;
	}
	// print a signed integer
	template <class I>
	inline void print (I &x) {
		if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;
		while (x) qu[++ qr] = x % 10 + '0',  x /= 10;
		while (qr) putc (qu[qr --]);
	}
	//no need to call flush at the end manually!
	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
}
using io :: gi;
using io :: putc;
using io :: print;
const int p = 1e9+7;
int n,m,k;
int fac[3100],inv[3100];
inline int calc(int a,int b){return (a+b)%p;}
inline int del(int a,int b){return (a-b+p)%p;}
inline int mul(int a,int b){return 1ll*a*b%p;}
inline int ksm(int a,int x){int now = 1;for(;x;x>>=1,a=1ll*a*a%p) if(x&1) now = 1ll*now*a%p;return now;}
inline int sqr(int x){return 1ll*x*x%p;}
inline int C(int x,int y){return (y<0||y>x)?0:mul(fac[x],mul(inv[y],inv[x-y]));}
const int inv2 = ksm(2,p-2);
const int inv3 = ksm(3,p-2);
namespace pt1{
	int f[100][100],g[100];
	void work(){
		rep(i,1,n) g[i] = mul(i,mul(i-1,inv2));
		rep(i,1,n) rep(j,i-1,k) {
			f[i][j] = C(g[i],j);
			rep(t,1,i-1) rep(sz,t-1,j) //t为1所在联通快大小,sz为边数
			    f[i][j] = del(f[i][j],mul(mul(f[t][sz],C(g[i-t],j-sz)),C(i-1,t-1))); 
		}
	}
}using namespace pt1;
namespace pt2{
	void work(){
		int ans = mul(f[n-1][k-2],C(n-1,2));
		int tmp = 0;
		rep(i,1,n-2) rep(j,0,k-2)
		    tmp = calc(tmp,mul(  mul( i , n-1-i )  ,  mul( f[i][j] , mul( f[n-1-i][k-2-j] , C(n-1,i) ) )));
		ans = calc(ans,mul(tmp,inv2));
		printf("%d\n",ans);
	}
}using namespace pt2;
namespace pt3{
	void work(){
		int ans = mul(f[n-2][k-4],mul(C(n-2,2),C(n-2,2)));
		ans = calc(ans,mul(mul(f[n-2][k-3],C(n-2,2) ) ,2 ));
		ans = calc(ans,mul(mul(f[n-2][k-3],C(n-2,1)) ,1 ));
		int fuck1 = 0 , fuck2 = 0;
		rep(i,1,n-3) rep(j,0,k-4){
			int tmp = mul(f[i][j],mul(f[n-2-i][k-4-j],C(n-2,i)));
			fuck1 = calc(fuck1,mul( mul(sqr(i) , sqr(n-2-i)) , tmp ));
			fuck2 = calc(fuck2,mul( mul(2,tmp) ,mul(  mul(i,n-2-i)  ,  C(i,2)  ) ) );
		}
		fuck1 = mul(fuck1,inv2);
		ans = calc(ans,calc(fuck1,fuck2)); fuck1 = 0;
		rep(i,1,n-3) rep(j,0,k-3){
		    fuck1 = calc(fuck1,mul( f[i][j] , mul( f[n-2-i][k-3-j] , mul( C(n-2,i) , mul( i , n-2-i ) ) ) )  );
		}
		ans = calc(ans,fuck1);
		fuck1 = 0;
		rep(i,1,n-4){
			rep(j,1,n-4) if(i+j <= n-3){
				int t = n - 2 - i - j;
				rep(a,0,k-4) if(f[i][a]){
					rep(b,0,k-4-a) if(f[j][b]){
						int c = k-4-a-b;
						if(!f[t][c]) continue;
						fuck2 = mul( f[i][a] , mul( f[j][b] , f[t][c] ) );
						fuck2 = mul( fuck2 , mul(  C( n-2 , i ) , C( n-2-i , j )  )  );
						fuck1 = calc( fuck1 , mul(  fuck2 , mul(  sqr(i) , mul( j , mul( 1 , t ) )  ) ) );
					}
				}
			}
		}
		mul(fuck1,32);
		printf("%d\n",calc(ans,fuck1));
    }
}using namespace pt3;
int main(){
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	gi(n); gi(m); gi(k);
	fac[0] = inv[0] = 1;
	rep(i,1,3000) fac[i] = 1ll*fac[i-1]*i%p,inv[i] = ksm(fac[i],p-2);
	if(m == 0) pt1::work(),printf("%d\n",pt1::f[n][k]);
	else if(m == 1) pt1::work(),pt2::work();
	else pt1::work(),pt3::work();
    return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值