【CodeChef】—Sum of Cubes(斯特林数+容斥+三元环计数)

传送门


fs,if_{s,i}表示边ii在点集ss中是否出现

答案就是s(ifs,i)k\sum_{s}(\sum_{i}f_{s,i})^k

考虑把kk次方拆开就是i=0kSk,ii!(fs,ii)\sum_{i=0}^{k}S_{k,i}i!{\sum_{f_{s,i}}\choose i}

考虑这个式子的组合意义,就是把一个置换的所有循环的集合的所有子集选出来
一个大小为ii的子集的贡献就是Sk,ii!S_{k,i}i!

就只需要把所有大小在kk以内的集合贡献求出来
考虑一个边的集合只需要考虑有哪些点必须选
剩下随便选或不选

一条边和两条边很好求
主要3条边
有5种情况
1、AB,CD,EFA-B,C-D,E-F
2、ABC,DEA-B-C,D-E
3、ABCDA-B-C-D
4、AB,AC,ADA-B,A-C,A-D
5、ABCAA-B-C-A

5要用到三元环计数
然后依次推4、3、2、1,中间要容斥一下

然后就完了

#include<bits/stdc++.h>
using namespace std;
const int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ob==ib)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ob==ib)?EOF:*ib++;
}
#define gc getchar
inline int read(){
	char ch=gc();
	int res=0,f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
#define ll long long
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define pob pop_back
#define cs const
#define poly vector<int>
cs int mod=1e9+7;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
inline void Add(int &a,int b){a=add(a,b);}
inline int dec(int a,int b){return a>=b?a-b:a-b+mod;}
inline void Dec(int &a,int b){a=dec(a,b);}
inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,a=mul(a,a))(b&1)?(res=mul(res,a)):0;return res;}
inline void chemx(int &a,int b){a<b?a=b:0;}
inline void chemn(int &a,int b){a>b?a=b:0;}
cs int N=100005;
int s[4][4];
inline void init(){
	s[0][0]=1;
	for(int i=1;i<=3;i++)
	for(int j=1;j<=3;j++)
	s[i][j]=add(s[i-1][j-1],mul(s[i-1][j],j));
}
inline ll C3(int n){
	return 1ll*(n-1)*(n-2)*n/6;
}
vector<int> e[N];
int n,m,k,in[N];
inline int solve1(){
	if(n>=2)return mul(m,mul(ksm(2,n-2),s[k][1]));
	else return 0;
}
inline int solve2(){
	ll tot=0;int res=0;
	for(int i=1;i<=n;i++)
	for(int &v:e[i])tot+=in[v]-1;
	tot/=2;
	if(n>=3)Add(res,mul(tot%mod,mul(ksm(2,n-3),s[k][2])));
	tot=1ll*m*(m-1)/2-tot;
	if(n>=4)Add(res,mul(tot%mod,mul(ksm(2,n-4),s[k][2])));
	return mul(res,2);
}
int cnt[N];
inline bool comp(int u,int v){
	return (in[u]==in[v])?u>v:in[u]>in[v];
}
inline ll calc2(){
	ll res=0;
	for(int i=1;i<=n;i++)
	res+=1ll*in[i]*(in[i]-1)/2*(m-2);
	return res;
}
inline ll calc3(){
	ll res=0;
	for(int i=1;i<=n;i++)
	for(int &v:e[i])
	res+=1ll*(in[i]-1)*(in[v]-1);
	return res/2;
}
inline ll calc4(){
	ll res=0;
	for(int i=1;i<=n;i++)
	res+=C3(in[i]);
	return res;
}
inline ll calc5(){
	ll res=0;
	for(int u=1;u<=n;u++){
		for(int &v:e[u])if(comp(u,v))cnt[v]++;
		for(int &v:e[u])if(comp(u,v))
		for(int &z:e[v])if(comp(v,z))
		if(cnt[z])res++;
		for(int &v:e[u])if(comp(u,v))cnt[v]=0;
	}
	return res;
}
inline int solve3(){
	ll cnt1=0,cnt2=0,cnt3=0,cnt4=0,cnt5=0;
	cnt5=calc5(),cnt4=calc4(),cnt3=calc3()-cnt5*3;
	cnt2=calc2()-cnt4*3-cnt5*3-cnt3*2,cnt1=C3(m)-cnt2-cnt3-cnt4-cnt5;
	cnt1%=mod,cnt2%=mod,cnt3%=mod,cnt4%=mod,cnt5%=mod;
	int res=0;
	if(cnt1)Add(res,mul(cnt1,ksm(2,n-6)));
	if(cnt2)Add(res,mul(cnt2,ksm(2,n-5)));
	if(cnt3)Add(res,mul(cnt3,ksm(2,n-4)));
	if(cnt4)Add(res,mul(cnt4,ksm(2,n-4)));
	if(cnt5)Add(res,mul(cnt5,ksm(2,n-3)));
	return mul(res,mul(s[k][3],6));
}
inline void solve(){
	n=read(),m=read(),k=read();int res=0;
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		in[u]++,in[v]++;
		e[u].pb(v),e[v].pb(u);
	}
	if(1<=k)Add(res,solve1());
	if(2<=k)Add(res,solve2());
	if(3<=k)Add(res,solve3());
	cout<<res<<'\n';
	memset(in,0,sizeof(int)*(n+1));
	for(int i=1;i<=n;i++)e[i].clear();
}
int main(){
	init();
	int T=read();
	while(T--)solve();
}
posted @ 2019-08-21 19:12  Stargazer_cykoi  阅读(115)  评论(0编辑  收藏  举报